web-dev-qa-db-fra.com

Comment faire une demande synchrone en utilisant Alamofire?

J'essaie de faire une demande synchrone en utilisant Alamofire. J'ai regardé Stackoverflow et trouvé cette question: rendre synchrone une demande alamofire asynchrone .

J'ai vu que la réponse acceptée utilise completion pour rendre Alamofire la demande synchrone mais je ne peux pas le faire fonctionner. Voici mon code simplifié:

func loadData(completion: (Bool)) -> (Int, [String], [String], [String]){

    Alamofire.request(url!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { response in

        switch(response.result) {
        case .success(_):
            if let JSON = response.result.value as! [[String : AnyObject]]!{
                 //Here I retrieve the data
            }

            completion(true)
            break

        case .failure(_):
            print("Error")
            completion(false)
            break  
        }
   }

   return (numberRows, nameArray, ageArray, birthdayArray)
}

Avec ce code, j'obtiens une erreur lors de la tentative de création de completion(bool value). L'erreur que je reçois est la suivante:

Impossible d'appeler une valeur de type non fonction 'Bool'

J'ai essayé d'utiliser de nombreux exemples en utilisant la complétion pour obtenir les valeurs de manière synchrone (car j'ai besoin de récupérer les données avant de les afficher sur une table et en même temps obtenir le nombre de lignes de cette table) sans succès.

Comment puis-je utiliser cette complétion pour obtenir une réponse synchrone?

Merci d'avance!

14
Francisco Romero

lorsque vous utilisez le gestionnaire d'achèvement, n'utilisez pas return.

func loadData(completion: @escaping (_ number: Int, _ strArr1: [String], _ strArr2: [String], _ strArr3: [String]) -> ()){

  Alamofire.request(url!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { response in

    switch(response.result) {
    case .success(_):
        if let JSON = response.result.value as! [[String : AnyObject]]!{
            //Here I retrieve the data
        }
        completion(number: numberRows, strArr1 : nameArray, strArr2 : ageArray, strArr3: birthdayArray)
        break

    case .failure(_):
        print("Error")
        completion(number: numberRows, strArr1 : nameArray, strArr2 : ageArray, strArr3: birthdayArray)
        break
    }
  }
}

loadData (completion: { (number, strArr1, strArr2, strArr3) in
    // do it
    // for exapmple
    self.number = number
    self.strArr1 = strArr1
    // and so on

})

ou si vous souhaitez renvoyer une valeur dans la fermeture, vous devez utiliser le gestionnaire d'achèvement pour renvoyer toute valeur ou quelque chose comme, par exemple si vous voulez renvoyer une valeur booléenne:

func loadData(completion:(number: numberRows, strArr1 : nameArray, strArr2 : ageArray, strArr3: birthdayArray) -> (Bool))

et dans le loadData

loadData( completion: { ( number, strArr1, strArr2, strArr3 ) -> (Bool) in
       # code 
       return False
})

ou certains pensent autre chose.

J'utilise Swift 3. mais si vous voulez une autre version de Swift attention aux noms de paramètres externes et aux noms de paramètres internes, comme: @escaping (_ number: Int, _ strArr1: [String], _ strArr2: [String], _ strArr3: [String]) -> ())

si vous voulez définir des noms de paramètres externes, il suffit de déposer _ et de définir le nom des paramètres.

4
Ali Zahedi

Notez que faire des demandes synchrones est fortement déconseillé par Apple, pour les raisons indiquées ici .

Dans cet exemple, je simplifie l'appel, si vous avez plus d'informations, telles que le contenu des cellules, je vous suggère de jeter un coup d'œil à SwiftyJSON et de renvoyer l'intégralité du blob JSON, puis de l'analyser dans les méthodes pertinentes (numberOfRows, etc. .).

class TableViewJSONAsynchCalls: UIViewController, UITableViewDelegate, UITableViewDataSource {
    var tableView = UITableView()
    var numberOfRows = 0;

    override func viewDidLoad() {
        loadData { (didCompleteRequest) in
            if (didCompleteRequest) {
                tableView.delegate = self
                tableView.dataSource = self
                tableView.reloadData()
            } else {
                // Handle error if data was not loaded correctly
            }
        }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return numberOfRows;
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("selected")
    }

    func loadData(completion: (Bool) -> Void) {
        // Make asynchronous call using alamofire
        // This simulates you parsing the JSON and setting the relevant variables, 
        // personally I would recommend you return a JSON blob and then 
        // parse it in the relevant methods.
        sleep(2)
        // If call is successful
        self.numberOfRows = 10
        completion(true)

    }
}
1
FredLoh