2017-02-09 2 views
1

J'essaie de créer mon premier projet avec swift 3.Synchronisation des fonctions asynchrones

J'essaie d'obtenir des données de mon API. Cela fonctionne très bien si je démarre manuellement la fonction. J'ai besoin de synchroniser la demande asynchrone.

J'ai besoin de déclencher mes fonctions 3 fois et attendre les autres pour terminer.

makeGetCall(URLstring: "api1") 

attente pour terminer

makeGetCall(URLstring: "api2") 

attente pour terminer

makeGetCall(URLstring: "api3") 

Définir ce à fond et de déclencher toutes les 5 secondes.

func makeGetCall(URLstring: String, update: Bool) { 

    let completeURL = "http://myapi/" + URLstring 


    // Set up the URL request 
    guard let url = URL(string: completeURL) else { 
     print("Error: cannot create URL") 
     return 
    } 
    let urlRequest = URLRequest(url: url) 

    // set up the session 
    let config = URLSessionConfiguration.default 
    let session = URLSession(configuration: config) 

    // make the request 
    let task = session.dataTask(with: urlRequest) { 
     (data, response, error) in 
     // check for any errors 
     guard error == nil else { 
      print("error calling GET on /todos/1") 
      print(error as Any) 
      return 
     } 
     // make sure we got data 
     guard let responseData = data else { 
      print("Error: did not receive data") 
      return 
     } 

      // parse the result as XML 
     if URLstring == "devicelist.cgi" { 
      self.readDevice(XMLData: responseData) 
     } 

     if URLstring == "statelist.cgi" { 
      self.readDeviceData(XMLData: responseData, update: update) 
     } 

     if URLstring == "functionlist.cgi" { 
      self.readGewerke(XMLData: responseData) 
     } 
    } 

    task.resume() 

} 

Quelqu'un peut-il vous aider s'il vous plaît.

Hagen

C'est ce que j'ai essayé avec gestionnaire d'achèvement:

override func viewDidLoad() { 
    super.viewDidLoad() 

    makeGetCall(input: "statelist.cgi") { 
     (result: Bool) in 
     print("finished statelist") 

    } 
    makeGetCall(input: "devicelist.cgi") { 
     (result: Bool) in 
     print("finished devicelist") 
    } 


    makeGetCall(input: "functionlist.cgi") { 
     (result: Bool) in 
     print("finished functionlist") 
    } 

} 

func makeGetCall(input: String, completion: @escaping (_ result: Bool) -> Void) { 



    let completeURL = "http://192.168.0.25/addons/xmlapi/" + input 


    // Set up the URL request 
    guard let url = URL(string: completeURL) else { 
     print("Error: cannot create URL") 
     return 
    } 
    let urlRequest = URLRequest(url: url) 

    // set up the session 
    let config = URLSessionConfiguration.default 
    let session = URLSession(configuration: config) 

    // make the request 
    let task = session.dataTask(with: urlRequest) { 
     (data, response, error) in 
     // check for any errors 
     guard error == nil else { 
      print("error calling GET on /todos/1") 
      print(error as Any) 
      return 
     } 
     // make sure we got data 
     guard data != nil else { 
      print("Error: did not receive data") 
      return 
     } 
     completion(true) 

    } 

    task.resume() 


} 

Si je mets les 3 appels ensemble, il a travaillé comme il se doit. Je chose qu'il faut aussi travailler avec GCD, mais la plupart des exemples pour rapide 2.

makeGetCall(input: "devicelist.cgi") { 
     (result: Bool) in 
     print("finished devicelist") 
     self.makeGetCall(input: "functionlist.cgi") { 
      (result: Bool) in 
      print("finished functionlist") 
      self.makeGetCall(input: "statelist.cgi") { 
       (result: Bool) in 
       print("finished statelist") 

      } 
     } 
    } 

Peut-être que maintenant quelqu'un peut aider.

Merci Hagen

+0

Ajouter un gestionnaire d'achèvement 'makeGetCall()' 'et utiliser un DispatchGroup' attendre ou être averti. – shallowThought

+0

J'ai essayé de résoudre mon problème mais je n'ai pas travaillé. Quelqu'un peut-il me donner des conseils? – Hagen

+0

Montrez ce que vous avez essayé avec le gestionnaire d'achèvement – shallowThought

Répondre

1

Utilisez un DispatchGroup pour être averti quand il arrive quelque chose.

override func viewDidLoad() { 
    super.viewDidLoad() 

    let stateListGroup = DispatchGroup() 

    stateListGroup.enter() 
    makeGetCall(input: "statelist.cgi") { 
     (result: Bool) in 
     print("finished statelist") 
     stateListGroup.leave() 
    } 

    let deviceListGroup = DispatchGroup() 
    deviceListGroup.enter() 

    // the notify closure is called when the (stateList-) groups enter and leave counts are balanced. 
    stateListGroup.notify(queue: DispatchQueue.main) { 
     self.makeGetCall(input: "devicelist.cgi") { 
      (result: Bool) in 
      print("finished devicelist") 
      deviceListGroup.leave() 
     } 
    } 

    let functionListGroup = DispatchGroup() 
    functionListGroup.enter() 

    deviceListGroup.notify(queue: DispatchQueue.main) { 
     self.makeGetCall(input: "functionList") { 
      (result: Bool) in 
      print("finished functionlist") 
      functionListGroup.leave() 
     } 
    } 

    functionListGroup.notify(queue: DispatchQueue.main) { 
     print("update ui here") 
    } 
} 

Prints:

statelist.cgi 
finished statelist 
devicelist.cgi 
finished devicelist 
functionList 
finished functionlist 
update ui here 

Gardez à l'esprit que le gestionnaire d'achèvement de session.dataTask() est appelée sur une file d'attente d'arrière-plan, donc je vous recommande d'envoyer completion(true) sur la file d'attente principale pour éviter un comportement inattendu:

DispatchQueue.main.async { 
    completion(true) 
} 
+0

Merci beaucoup shallowThought. Je l'ai modifié pour group.notify (file d'attente: DispatchQueue.main) et maintenant il fonctionne comme il se doit. – Hagen

+0

Oh, désolé. Écrit dans le métro ... Correction de la mise à jour de la réponse. Ici à SO nous remercions en votant/acceptant la réponse btw. – shallowThought