Domanda Come restituire il valore da Alamofire


Sto effettuando chiamate url tramite un'API che ho creato usando swift come segue:

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
  }

}

Io chiamo questa API nella mia UITableViewController per popolare la tabella con la libreria SwiftyJSON. Comunque il mio returnData dall'API è sempre vuoto. Non ci sono problemi con le chiamate Alomofire poiché posso recuperare con successo il valore. Il mio problema è come dovrei portare questo data sul mio controller di visualizzazione tabella?

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

44
2017-12-09 23:15


origine


risposte:


Come sottolinea Mattt, Alamofire sta restituendo dati in modo asincrono tramite a completionHandler modello, quindi devi fare lo stesso. Non puoi return il valore immediatamente, ma tu invece vuoi usarlo Void restituisce il tipo e utilizza invece un modello di chiusura del gestore di completamento.

In Swift 3 e Alamofire 4, potrebbe essere:

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

Quindi, quando vuoi chiamarlo, lo usi completionHandler parametro (in chiusura finale, se lo desideri):

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

83
2017-12-10 04:05



Dal README di Alamofire (corsivo aggiunto):

La rete in Alamofire viene eseguita in modo asincrono. La programmazione asincrona può essere fonte di frustrazione per i programmatori che non hanno familiarità con il concetto, ma ci sono ottime ragioni per farlo in questo modo.

Anziché bloccare l'esecuzione per attendere una risposta dal server, viene specificata una richiamata per gestire la risposta una volta ricevuta. Il risultato di una richiesta è disponibile solo nell'ambito di un gestore di risposta. Qualsiasi esecuzione dipendente dalla risposta o dai dati ricevuti dal server deve essere eseguita all'interno di un gestore.


10
2017-12-09 23:41



Di seguito è riportato il flusso completo per eseguire il 'Login azione' usando Alamofire e Swift.

Alamofire v3.3 Swift 2.2 Xcode 7.3

ho usato GCD e MBProgressHUD per mia comodità. Refactoring e usa come preferisci :)

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

}

2
2018-04-08 14:20



Per analizzare un json usando Swifty JSON, ecco come lo sto facendo.

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

0
2017-10-13 05:09



Dettagli

xCode 9.1, Swift 4

Caratteristiche:

  • Codice facilmente leggibile
  • Modelli pronti (è facile aggiungere più richieste)
  • Soluzione integrata con elaborazione dati asincrona
  • Esempi completi

Esempio 1

Restituisci i dati usando la chiusura

Data1.searchRequest(term: "jack johnson") { json, error  in
     print(error ?? "nil")
     print(json ?? "nil")
     print("Update views")
}

Campione completo 1

Classe dati

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

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

Campione 2

Restituisci i dati usando delegato

// ....
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")
    }
}

Campione completo 2

Classe dati

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

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

Esempio 3

Restituisci i dati usando PromiseKit

_ = data.searchRequest(term: "jack johnson").then { response in
      print(response.error ?? "nil")
      print(response.json ?? "nil")
      print("Update views")
      return .void
}

Campione completo 3

Classe dati       import Alamofire       importa 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

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

0
2017-12-01 14:19