2016-10-10 1 views
7

J'essaie de faire une demande synchrone en utilisant Alamofire. J'ai regardé Stackoverflow et j'ai trouvé cette question: making an asynchronous alamofire request synchronous.Comment faire une requête synchrone avec Alamofire?

J'ai vu que la réponse acceptée utilise completion pour faire Alamofire demande synchrone mais je ne peux pas le faire fonctionner. Ceci est 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, je reçois une erreur en essayant de faire completion(bool value). L'erreur que je reçois est la suivante:

ne peut pas appeler valeur de type non-fonction « Bool »

J'ai essayé d'utiliser beaucoup d'exemples en utilisant la fin pour obtenir les valeurs de manière synchrone (parce que J'ai besoin de récupérer les données avant de les montrer sur une table et en même temps obtenir le nombre de lignes de cette table) sans succès. Comment utiliser cette complétion pour obtenir une réponse synchrone?

Merci d'avance!

+0

Je vous recommande d'implémenter votre propre méthode. Apple a fortement déconseillé les appels réseau synchrones. Jetez un oeil à ceci: http://stackoverflow.com/questions/31557688/synchronous-url-request-on-swift-2 – FredLoh

+0

https://github.com/Alamofire/Alamofire/issues/1147, vous devez voir ce blog. J'espère que cela vous aidera. –

+0

Il semble que vous ne compreniez pas comment les méthodes asynchrones fonctionnent, en particulier avec les rappels d'achèvement. Au lieu de forcer les appels synchrones, investissez cet effort dans la compréhension de la programmation asynchrone. – vikingosegundo

Répondre

1

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 voulez retourner une valeur dans la fermeture, vous devez utiliser gestionnaire d'achèvement pour le retour une valeur ou quelque chose comme, par exemple, si vous voulez retourner 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 d'autres pensent autrement.

-je utiliser rapidement 3. mais si vous voulez une autre version de rapide attention sur les noms externes des paramètres et des noms de paramètres internes, comme: @escaping (_ number: Int, _ strArr1: [String], _ strArr2: [String], _ strArr3: [String]) ->())

si vous souhaitez définir des noms de paramètres externes, juste besoin déposer _ et nom défini pour paramètres.

+0

Merci beaucoup! Vous m'avez donné l'indice pour résoudre mon problème! :) –

+0

Vous l'avez. Je suis tellement content de pouvoir aider. ;-) –

0

Notez que la fabrication de requêtes synchrones est fortement déconseillée par Apple, pour les raisons indiquées here.

Dans cet exemple, je simplifie l'appel, si vous avez plus d'informations, telles que le contenu des cellules, je vous suggère de regarder SwiftyJSON et de renvoyer l'intégralité du blob JSON, puis de l'analyser dans les méthodes appropriées (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) 

    } 
} 
+0

la fonction de veille ne bloque pas l'interface utilisateur également? –

+0

Il va, je l'utilise pour simuler un appel synchrone.Une requête réseau synchrone bloque le thread principal, ce qui explique pourquoi il est fortement déconseillé. À moins que vous ne le fassiez sur un thread séparé (ce qui vous donnera d'autres problèmes comme l'impossibilité d'annuler la requête, etc.), à ce stade, vous pourriez aussi bien le rendre asynchrone. – FredLoh

+0

Le problème est que, comme j'ai besoin de récupérer le nombre de lignes d'une table avant que la table est affichée, je dois le rendre synchrone (ou du moins est le seul moyen que je pense que je peux me concentrer). Si je le fais de manière asynchrone, j'obtiens que la table aura 0 lignes. –