web-dev-qa-db-fra.com

Comment retourner de la valeur d'Alamofire

Je passe des appels via une API que j'ai créée à l'aide de Swift, comme suit:

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
  }

}

J'appelle cette API dans ma UITableViewController pour remplir la table avec la bibliothèque SwiftyJSON. Cependant, ma returnData de l'API est toujours vide. Il n’ya aucun problème avec les appels Alomofire car je peux récupérer une valeur avec succès. Mon problème est de savoir comment je suis supposé porter cette data sur mon contrôleur de vue de table? 

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

Comme le souligne mattt, Alamofire renvoie les données de manière asynchrone via un modèle completionHandler. Vous devez donc en faire de même. Vous ne pouvez pas simplement return la valeur immédiatement, mais vous souhaitez utiliser le type de retour Void et utiliser un modèle de fermeture du gestionnaire d'achèvement.

Dans Swift 3 et Alamofire 4, cela pourrait ressembler à:

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

Ensuite, lorsque vous souhaitez l'appeler, vous utilisez le paramètre completionHandler (en fin de liste, si vous le souhaitez):

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
88
Rob

De Alamofire README (non souligné dans l'original):

La mise en réseau dans Alamofire se fait de manière asynchrone. La programmation asynchrone peut être une source de frustration pour les programmeurs peu familiarisés avec le concept, mais il y a de très bonnes raisons de le faire de cette façon.

Plutôt que de bloquer l'exécution pour attendre une réponse du serveur, un rappel est spécifié pour gérer la réponse une fois qu'elle est reçue. Le résultat d'une requête est uniquement disponible dans le périmètre d'un gestionnaire de réponses. Toute exécution subordonnée à la réponse ou aux données reçues du serveur doit être effectuée dans un gestionnaire .

11
mattt

Vous trouverez ci-dessous la marche à suivre pour exécuter 'Action de connexion' avec Alamofire et Swift.

Alamofire v3.3 Swift 2.2 Xcode 7.3

J'ai utiliséGCDet MBProgressHUD pour ma propre commodité. Refacturer et utiliser comme vous le souhaitez :)

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":"[email protected]","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
n.by.n

Détails

xCode 9.1, Swift 4

Caractéristiques:

  • Code lisible facilement
  • Modèles prêts (il est facile d'ajouter plus de demandes)
  • Solution embarquée avec traitement de données asynchrone
  • Exemples complets

Échantillon 1

Renvoyer les données en utilisant la fermeture

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

Échantillon complet 1

Classe de données

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

Échantillon 2

Renvoyer des données en utilisant un délégué

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

Échantillon complet 2

Classe de données

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

Échantillon 3

Renvoyer des données en utilisant PromiseKit

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

Échantillon complet 3

Classe de données importer Alamofire importer 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
Vasily Bodnarchuk

Pour analyser un JSON utilisant Swifty JSON, voici comment je le fais. 

Pour @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
kishorer747