I am making url calls thru an API that I created using swift as follows:
我通过swift创建的API进行url调用,如下所示:
class API {
let apiEndPoint = "endpoint"
let apiUrl:String!
let consumerKey:String!
let consumerSecret:String!
var returnData = [:]
init(){
self.apiUrl = "https://myurl.com/"
self.consumerKey = "my consumer key"
self.consumerSecret = "my consumer secret"
}
func getOrders() -> NSDictionary{
return makeCall("orders")
}
func makeCall(section:String) -> NSDictionary{
let params = ["consumer_key":"key", "consumer_secret":"secret"]
Alamofire.request(.GET, "\(self.apiUrl)/\(self.apiEndPoint + section)", parameters: params)
.authenticate(user: self.consumerKey, password: self.consumerSecret)
.responseJSON { (request, response, data, error) -> Void in
println("error \(request)")
self.returnData = data! as NSDictionary
}
return self.returnData
}
}
I call this API in my UITableViewController
to populate the table with SwiftyJSON library. However my returnData
from the API is always empty. There is no problem with Alomofire calls as I can successfully retrieve value. My problem is how I am supposed to carry this data
over to my table view controller?
我在我的UITableViewController中调用这个API,用SwiftyJSON库填充表。但是,我从API中返回的数据总是空的。Alomofire调用没有问题,因为我可以成功地检索值。我的问题是如何将这些数据传送到表视图控制器?
var api = API()
api.getOrders()
println(api.returnData) // returnData is empty
5 个解决方案
#1
82
As mattt points out, Alamofire is returning data asynchronously via a completionHandler
pattern, so you must do the same. You cannot just return
the value immediately, but you instead want to use Void
return type and instead use a completion handler closure pattern.
正如mattt指出的,Alamofire通过completionHandler模式异步返回数据,所以您必须做同样的事情。您不能立即返回值,而是要使用Void返回类型,而是使用一个完成处理程序闭包模式。
In Swift 3 and Alamofire 4, that might look like:
在Swift 3和Alamofire 4中,这看起来像是:
func getOrders(completionHandler: @escaping (NSDictionary?, Error?) -> ()) {
makeCall("orders", completionHandler: completionHandler)
}
func makeCall(_ section: String, completionHandler: @escaping (NSDictionary?, Error?) -> ()) {
let params = ["consumer_key":"key", "consumer_secret":"secret"]
Alamofire.request("\(apiUrl)/\(apiEndPoint + section)", parameters: params)
.authenticate(user: consumerKey, password: consumerSecret)
.responseJSON { response in
switch response.result {
case .success(let value):
completionHandler(value as? NSDictionary, nil)
case .failure(let error):
completionHandler(nil, error)
}
}
}
Then, when you want to call it, you use this completionHandler
parameter (in trailing closure, if you want):
然后,当您想调用它时,您使用这个completionHandler参数(如果您愿意,在尾闭包中):
let api = API()
api.getOrders() { responseObject, error in
// use responseObject and error here
print("responseObject = \(responseObject); error = \(error)")
return
}
// but don't try to use them here
#2
10
From the Alamofire README (emphasis added):
从阿拉莫菲尔自述(强调补充):
Networking in Alamofire is done asynchronously. Asynchronous programming may be a source of frustration to programmers unfamiliar with the concept, but there are very good reasons for doing it this way.
Alamofire中的网络是异步完成的。异步编程可能会让不熟悉这个概念的程序员感到沮丧,但是有很好的理由这样做。
Rather than blocking execution to wait for a response from the server, a callback is specified to handle the response once it's received. The result of a request is only available inside the scope of a response handler. Any execution contingent on the response or data received from the server must be done within a handler.
不是阻塞执行以等待服务器的响应,而是指定一个回调来处理接收到的响应。请求的结果仅在响应处理程序的范围内可用。任何基于从服务器接收的响应或数据的执行都必须在处理程序中完成。
#3
2
Following is the complete flow for performing the 'Login Action' using Alamofire and Swift.
下面是使用Alamofire和Swift执行“登录操作”的完整流程。
Alamofire v3.3 Swift 2.2 Xcode 7.3
Alamofire v3.3 Swift 2.2 Xcode 7.3。
I have used GCD and MBProgressHUD for my own convenience. Refactor and use as you like :)
为了方便自己,我使用了GCD和MBProgressHUD。重构和使用你喜欢的:)
func loginBtnTapped(sender: AnyObject) {
MBProgressHUD.showHUDAddedTo(self.view, animated: true)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let loginInfo : Dictionary<String,AnyObject> = ["email":"abc@g.com","password":"abc123"]
self.loginUser(loginInfo) { responseObject, error in
print("\(responseObject) \n \(error) ")
// Parsing JSON Below
let status = Int(responseObject?.objectForKey("status") as! String)
if status == 1 {
// Login Successfull...Move To New VC
}
else {
print(responseObject?.objectForKey("message"))! as! String)
}
return
}
dispatch_async(dispatch_get_main_queue()) {
MBProgressHUD.hideHUDForView(self.view, animated: true)
}
}
}
func loginUser(parameters:NSDictionary, completionHandler: (NSDictionary?, NSError?) -> ()) {
self.postRequest("http://qa.company.com/project/index.php/user/login",
paramDict: parameters as? Dictionary<String, AnyObject>,
completionHandler: completionHandler)
}
func postRequest(urlString: String, paramDict:Dictionary<String, AnyObject>? = nil,
completionHandler: (NSDictionary?, NSError?) -> ()) {
Alamofire.request(.POST, urlString, parameters: paramDict)
.responseJSON { response in
switch response.result {
case .Success(let JSON):
completionHandler(JSON as? NSDictionary, nil)
case .Failure(let error):
completionHandler(nil, error)
}
}
}
#4
0
To parse a json using Swifty JSON, here is how i am doing it.
For @Jenita _Alice4Real
要使用Swifty json解析json,我的做法如下。对于@Jenita _Alice4Real
func uploadScans(parameters: [String: AnyObject], completionHandler: (AnyObject?, NSError?) -> ()) {
makePostCall(CommonFunctions().getSaveSKUDataUrl(), parameters: parameters,completionHandler: completionHandler)
}
func makePostCall(url: String, parameters: [String: AnyObject], completionHandler: (AnyObject?, NSError?) -> ()) {
Alamofire.request(.POST, url, parameters: parameters)
.responseJSON { response in
switch response.result {
case .Success(let value):
completionHandler(value, nil)
case .Failure(let error):
completionHandler(nil, error)
}
}
}
uploadScans(params) { responseObject, error in
let json = JSON(responseObject!)
}
#5
0
Details
xCode 9.1, Swift 4
xCode 9.1,斯威夫特4
Features:
特点:
- Easy readable code
- 简单可读的代码
- Ready templates (it's easy to add more requests)
- 准备好的模板(很容易添加更多的请求)
- Embedded solution with asynchronous data processing
- 具有异步数据处理的嵌入式解决方案
- Full examples
- 完整的例子
Sample 1
Return data using closure
返回数据使用闭包
Data1.searchRequest(term: "jack johnson") { json, error in
print(error ?? "nil")
print(json ?? "nil")
print("Update views")
}
Full sample 1
Data class
数据类
import Alamofire
class Data1 {
static fileprivate let queue = DispatchQueue(label: "requests.queue", qos: .utility)
static fileprivate let mainQueue = DispatchQueue.main
fileprivate class func make(request: DataRequest, closure: @escaping (_ json: [String: Any]?, _ error: Error?)->()) {
request.responseJSON(queue: Data1.queue) { response in
// print(response.request ?? "nil") // original URL request
// print(response.response ?? "nil") // HTTP URL response
// print(response.data ?? "nil") // server data
//print(response.result ?? "nil") // result of response serialization
switch response.result {
case .failure(let error):
Data1.mainQueue.async {
closure(nil, error)
}
case .success(let data):
Data1.mainQueue.async {
closure((data as? [String: Any]) ?? [:], nil)
}
}
}
}
class func searchRequest(term: String, closure: @escaping (_ json: [String: Any]?, _ error: Error?)->()) {
let request = Alamofire.request("https://itunes.apple.com/search?term=\(term.replacingOccurrences(of: " ", with: "+"))")
Data1.make(request: request) { json, error in
closure(json, error)
}
}
}
UIViewController
ui
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
Data1.searchRequest(term: "jack johnson") { json, error in
print(error ?? "nil")
print(json ?? "nil")
print("Update views")
}
}
}
Sample 2
Return data using delegate
使用委托返回数据
// ....
var data = Data2()
data.delegate = self
data.searchRequest(term: "jack johnson")
// ....
extension ViewController: Data2Delegate {
func searchRequest(response json: [String : Any]?, error: Error?) {
print(error ?? "nil")
print(json ?? "nil")
print("Update views")
}
}
Full sample 2
Data class
数据类
import Alamofire
protocol Data2Delegate: class {
func searchRequest(response json: [String: Any]?, error: Error?)
}
class Data2 {
fileprivate let queue = DispatchQueue(label: "requests.queue", qos: .utility)
fileprivate let mainQueue = DispatchQueue.main
weak var delegate: Data2Delegate?
fileprivate func make(request: DataRequest, closure: @escaping (_ json: [String: Any]?, _ error: Error?)->()) {
request.responseJSON(queue: queue) { response in
// print(response.request ?? "nil") // original URL request
// print(response.response ?? "nil") // HTTP URL response
// print(response.data ?? "nil") // server data
//print(response.result ?? "nil") // result of response serialization
switch response.result {
case .failure(let error):
self.mainQueue.async {
closure(nil, error)
}
case .success(let data):
self.mainQueue.async {
closure((data as? [String: Any]) ?? [:], nil)
}
}
}
}
func searchRequest(term: String) {
let request = Alamofire.request("https://itunes.apple.com/search?term=\(term.replacingOccurrences(of: " ", with: "+"))")
make(request: request) { json, error in
self.delegate?.searchRequest(response: json, error: error)
}
}
}
UIViewController
ui
import UIKit
class ViewController: UIViewController {
private var data = Data2()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
data.delegate = self
data.searchRequest(term: "jack johnson")
}
}
extension ViewController: Data2Delegate {
func searchRequest(response json: [String : Any]?, error: Error?) {
print(error ?? "nil")
print(json ?? "nil")
print("Update views")
}
}
Sample 3
Return data using PromiseKit
使用PromiseKit返回数据
_ = data.searchRequest(term: "jack johnson").then { response in
print(response.error ?? "nil")
print(response.json ?? "nil")
print("Update views")
return .void
}
Full sample 3
Data class import Alamofire import PromiseKit
数据类导入Alamofire导入PromiseKit
class Data3 {
fileprivate let queue = DispatchQueue(label: "requests.queue", qos: .utility)
fileprivate let mainQueue = DispatchQueue.main
fileprivate func make(request: DataRequest) -> Promise<(json:[String: Any]?, error: Error?)> {
return Promise { fulfill, reject in
request.responseJSON(queue: queue) { response in
// print(response.request ?? "nil") // original URL request
// print(response.response ?? "nil") // HTTP URL response
// print(response.data ?? "nil") // server data
//print(response.result ?? "nil") // result of response serialization
switch response.result {
case .failure(let error):
self.mainQueue.async {
fulfill((nil, error))
}
case .success(let data):
self.mainQueue.async {
fulfill(((data as? [String: Any]) ?? [:], nil))
}
}
}
}
}
func searchRequest(term: String) -> Promise<(json:[String: Any]?, error: Error?)> {
let request = Alamofire.request("https://itunes.apple.com/search?term=\(term.replacingOccurrences(of: " ", with: "+"))")
return make(request: request)
}
}
extension AnyPromise {
class var void: AnyPromise {
return AnyPromise(Promise<Void>())
}
}
UIViewController
ui
import UIKit
import PromiseKit
class ViewController: UIViewController {
private var data = Data3()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
_ = data.searchRequest(term: "jack johnson").then { response in
print(response.error ?? "nil")
print(response.json ?? "nil")
print("Update views")
return .void
}
}
}
#1
82
As mattt points out, Alamofire is returning data asynchronously via a completionHandler
pattern, so you must do the same. You cannot just return
the value immediately, but you instead want to use Void
return type and instead use a completion handler closure pattern.
正如mattt指出的,Alamofire通过completionHandler模式异步返回数据,所以您必须做同样的事情。您不能立即返回值,而是要使用Void返回类型,而是使用一个完成处理程序闭包模式。
In Swift 3 and Alamofire 4, that might look like:
在Swift 3和Alamofire 4中,这看起来像是:
func getOrders(completionHandler: @escaping (NSDictionary?, Error?) -> ()) {
makeCall("orders", completionHandler: completionHandler)
}
func makeCall(_ section: String, completionHandler: @escaping (NSDictionary?, Error?) -> ()) {
let params = ["consumer_key":"key", "consumer_secret":"secret"]
Alamofire.request("\(apiUrl)/\(apiEndPoint + section)", parameters: params)
.authenticate(user: consumerKey, password: consumerSecret)
.responseJSON { response in
switch response.result {
case .success(let value):
completionHandler(value as? NSDictionary, nil)
case .failure(let error):
completionHandler(nil, error)
}
}
}
Then, when you want to call it, you use this completionHandler
parameter (in trailing closure, if you want):
然后,当您想调用它时,您使用这个completionHandler参数(如果您愿意,在尾闭包中):
let api = API()
api.getOrders() { responseObject, error in
// use responseObject and error here
print("responseObject = \(responseObject); error = \(error)")
return
}
// but don't try to use them here
#2
10
From the Alamofire README (emphasis added):
从阿拉莫菲尔自述(强调补充):
Networking in Alamofire is done asynchronously. Asynchronous programming may be a source of frustration to programmers unfamiliar with the concept, but there are very good reasons for doing it this way.
Alamofire中的网络是异步完成的。异步编程可能会让不熟悉这个概念的程序员感到沮丧,但是有很好的理由这样做。
Rather than blocking execution to wait for a response from the server, a callback is specified to handle the response once it's received. The result of a request is only available inside the scope of a response handler. Any execution contingent on the response or data received from the server must be done within a handler.
不是阻塞执行以等待服务器的响应,而是指定一个回调来处理接收到的响应。请求的结果仅在响应处理程序的范围内可用。任何基于从服务器接收的响应或数据的执行都必须在处理程序中完成。
#3
2
Following is the complete flow for performing the 'Login Action' using Alamofire and Swift.
下面是使用Alamofire和Swift执行“登录操作”的完整流程。
Alamofire v3.3 Swift 2.2 Xcode 7.3
Alamofire v3.3 Swift 2.2 Xcode 7.3。
I have used GCD and MBProgressHUD for my own convenience. Refactor and use as you like :)
为了方便自己,我使用了GCD和MBProgressHUD。重构和使用你喜欢的:)
func loginBtnTapped(sender: AnyObject) {
MBProgressHUD.showHUDAddedTo(self.view, animated: true)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let loginInfo : Dictionary<String,AnyObject> = ["email":"abc@g.com","password":"abc123"]
self.loginUser(loginInfo) { responseObject, error in
print("\(responseObject) \n \(error) ")
// Parsing JSON Below
let status = Int(responseObject?.objectForKey("status") as! String)
if status == 1 {
// Login Successfull...Move To New VC
}
else {
print(responseObject?.objectForKey("message"))! as! String)
}
return
}
dispatch_async(dispatch_get_main_queue()) {
MBProgressHUD.hideHUDForView(self.view, animated: true)
}
}
}
func loginUser(parameters:NSDictionary, completionHandler: (NSDictionary?, NSError?) -> ()) {
self.postRequest("http://qa.company.com/project/index.php/user/login",
paramDict: parameters as? Dictionary<String, AnyObject>,
completionHandler: completionHandler)
}
func postRequest(urlString: String, paramDict:Dictionary<String, AnyObject>? = nil,
completionHandler: (NSDictionary?, NSError?) -> ()) {
Alamofire.request(.POST, urlString, parameters: paramDict)
.responseJSON { response in
switch response.result {
case .Success(let JSON):
completionHandler(JSON as? NSDictionary, nil)
case .Failure(let error):
completionHandler(nil, error)
}
}
}
#4
0
To parse a json using Swifty JSON, here is how i am doing it.
For @Jenita _Alice4Real
要使用Swifty json解析json,我的做法如下。对于@Jenita _Alice4Real
func uploadScans(parameters: [String: AnyObject], completionHandler: (AnyObject?, NSError?) -> ()) {
makePostCall(CommonFunctions().getSaveSKUDataUrl(), parameters: parameters,completionHandler: completionHandler)
}
func makePostCall(url: String, parameters: [String: AnyObject], completionHandler: (AnyObject?, NSError?) -> ()) {
Alamofire.request(.POST, url, parameters: parameters)
.responseJSON { response in
switch response.result {
case .Success(let value):
completionHandler(value, nil)
case .Failure(let error):
completionHandler(nil, error)
}
}
}
uploadScans(params) { responseObject, error in
let json = JSON(responseObject!)
}
#5
0
Details
xCode 9.1, Swift 4
xCode 9.1,斯威夫特4
Features:
特点:
- Easy readable code
- 简单可读的代码
- Ready templates (it's easy to add more requests)
- 准备好的模板(很容易添加更多的请求)
- Embedded solution with asynchronous data processing
- 具有异步数据处理的嵌入式解决方案
- Full examples
- 完整的例子
Sample 1
Return data using closure
返回数据使用闭包
Data1.searchRequest(term: "jack johnson") { json, error in
print(error ?? "nil")
print(json ?? "nil")
print("Update views")
}
Full sample 1
Data class
数据类
import Alamofire
class Data1 {
static fileprivate let queue = DispatchQueue(label: "requests.queue", qos: .utility)
static fileprivate let mainQueue = DispatchQueue.main
fileprivate class func make(request: DataRequest, closure: @escaping (_ json: [String: Any]?, _ error: Error?)->()) {
request.responseJSON(queue: Data1.queue) { response in
// print(response.request ?? "nil") // original URL request
// print(response.response ?? "nil") // HTTP URL response
// print(response.data ?? "nil") // server data
//print(response.result ?? "nil") // result of response serialization
switch response.result {
case .failure(let error):
Data1.mainQueue.async {
closure(nil, error)
}
case .success(let data):
Data1.mainQueue.async {
closure((data as? [String: Any]) ?? [:], nil)
}
}
}
}
class func searchRequest(term: String, closure: @escaping (_ json: [String: Any]?, _ error: Error?)->()) {
let request = Alamofire.request("https://itunes.apple.com/search?term=\(term.replacingOccurrences(of: " ", with: "+"))")
Data1.make(request: request) { json, error in
closure(json, error)
}
}
}
UIViewController
ui
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
Data1.searchRequest(term: "jack johnson") { json, error in
print(error ?? "nil")
print(json ?? "nil")
print("Update views")
}
}
}
Sample 2
Return data using delegate
使用委托返回数据
// ....
var data = Data2()
data.delegate = self
data.searchRequest(term: "jack johnson")
// ....
extension ViewController: Data2Delegate {
func searchRequest(response json: [String : Any]?, error: Error?) {
print(error ?? "nil")
print(json ?? "nil")
print("Update views")
}
}
Full sample 2
Data class
数据类
import Alamofire
protocol Data2Delegate: class {
func searchRequest(response json: [String: Any]?, error: Error?)
}
class Data2 {
fileprivate let queue = DispatchQueue(label: "requests.queue", qos: .utility)
fileprivate let mainQueue = DispatchQueue.main
weak var delegate: Data2Delegate?
fileprivate func make(request: DataRequest, closure: @escaping (_ json: [String: Any]?, _ error: Error?)->()) {
request.responseJSON(queue: queue) { response in
// print(response.request ?? "nil") // original URL request
// print(response.response ?? "nil") // HTTP URL response
// print(response.data ?? "nil") // server data
//print(response.result ?? "nil") // result of response serialization
switch response.result {
case .failure(let error):
self.mainQueue.async {
closure(nil, error)
}
case .success(let data):
self.mainQueue.async {
closure((data as? [String: Any]) ?? [:], nil)
}
}
}
}
func searchRequest(term: String) {
let request = Alamofire.request("https://itunes.apple.com/search?term=\(term.replacingOccurrences(of: " ", with: "+"))")
make(request: request) { json, error in
self.delegate?.searchRequest(response: json, error: error)
}
}
}
UIViewController
ui
import UIKit
class ViewController: UIViewController {
private var data = Data2()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
data.delegate = self
data.searchRequest(term: "jack johnson")
}
}
extension ViewController: Data2Delegate {
func searchRequest(response json: [String : Any]?, error: Error?) {
print(error ?? "nil")
print(json ?? "nil")
print("Update views")
}
}
Sample 3
Return data using PromiseKit
使用PromiseKit返回数据
_ = data.searchRequest(term: "jack johnson").then { response in
print(response.error ?? "nil")
print(response.json ?? "nil")
print("Update views")
return .void
}
Full sample 3
Data class import Alamofire import PromiseKit
数据类导入Alamofire导入PromiseKit
class Data3 {
fileprivate let queue = DispatchQueue(label: "requests.queue", qos: .utility)
fileprivate let mainQueue = DispatchQueue.main
fileprivate func make(request: DataRequest) -> Promise<(json:[String: Any]?, error: Error?)> {
return Promise { fulfill, reject in
request.responseJSON(queue: queue) { response in
// print(response.request ?? "nil") // original URL request
// print(response.response ?? "nil") // HTTP URL response
// print(response.data ?? "nil") // server data
//print(response.result ?? "nil") // result of response serialization
switch response.result {
case .failure(let error):
self.mainQueue.async {
fulfill((nil, error))
}
case .success(let data):
self.mainQueue.async {
fulfill(((data as? [String: Any]) ?? [:], nil))
}
}
}
}
}
func searchRequest(term: String) -> Promise<(json:[String: Any]?, error: Error?)> {
let request = Alamofire.request("https://itunes.apple.com/search?term=\(term.replacingOccurrences(of: " ", with: "+"))")
return make(request: request)
}
}
extension AnyPromise {
class var void: AnyPromise {
return AnyPromise(Promise<Void>())
}
}
UIViewController
ui
import UIKit
import PromiseKit
class ViewController: UIViewController {
private var data = Data3()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
_ = data.searchRequest(term: "jack johnson").then { response in
print(response.error ?? "nil")
print(response.json ?? "nil")
print("Update views")
return .void
}
}
}