Cómo devolver valor de Alamofire

Estoy haciendo llamadas de url a través de una API que creé usando swift de la siguiente manera:

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 } } 

Llamo a esta API en mi UITableViewController para completar la tabla con la biblioteca SwiftyJSON. Sin embargo, my returnData de la API siempre está vacío. No hay problema con las llamadas de Alomofire, ya que puedo recuperar el valor con éxito. Mi problema es cómo se supone que debo llevar estos data a mi controller de vista de tabla.

 var api = API() api.getOrders() println(api.returnData) // returnData is empty 

Como señala Mattt, Alamofire devuelve datos de forma asíncrona a través de un patrón completionHandler , por lo que debe hacer lo mismo. No puede return el valor inmediatamente, sino que desea utilizar el tipo de retorno de Void y, en su lugar, usar un patrón de cierre de controller de finalización.

En Swift 3 y Alamofire 4, eso podría parecer:

 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) } } } 

Luego, cuando quiera llamarlo, use este parámetro completionHandler (en el cierre posterior, si lo desea):

 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 

Del file README de Alamofire (sin cursivas):

La networking en Alamofire se realiza de forma asíncrona. La progtwigción asíncrona puede ser una fuente de frustración para los progtwigdores que no están familiarizados con el concepto, pero hay muy buenas razones para hacerlo de esta manera.

En lugar de bloquear la ejecución para esperar una respuesta del server, se especifica una callback para manejar la respuesta una vez que se recibe. El resultado de una request solo está disponible dentro del scope de un manejador de respuestas. Cualquier ejecución contingente en la respuesta o datos recibidos del server debe hacerse dentro de un manejador .

A continuación se muestra el flujo completo para realizar la 'Acción de inicio de session' con Alamofire y Swift.

Alamofire v3.3 Swift 2.2 Xcode 7.3

He utilizado GCD y MBProgressHUD para mi propia conveniencia. Refactor y usa como quieras 🙂

 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) } } } 

Para analizar un json usando Swifty JSON, así es como lo estoy haciendo.

Para @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!) }