1

J'utilise DispatchGroup.enter() et leave() pour traiter la fonction asynchrone reverseG d'une classe auxiliaire. Le problème est clair, j'utilise l'objet mainViewController pour appeler dispatchGroup.leave() de mainViewControllers dans la classe helper! Y a-t-il un moyen de le faire?swift 3 DispatchGroup leave provoque des plantages quand il est appelé dans la fonction de classe auxiliaire

Le même code fonctionne lorsque reverseG est déclaré dans le contrôleur de la vue principale.

class Geo { 
    var obj = ViewController() 

    static func reverseG(_ coordinates: CLLocation, _ completion: @escaping (CLPlacemark) ->()) { 
     let geoCoder = CLGeocoder() 
     geoCoder.reverseGeocodeLocation(coordinates) { (placemarks, error) in 
      if let error = error { 
       print("error: \(error.localizedDescription)") 
      } 
      if let placemarks = placemarks, placemarks.count > 0 { 
       let placemark = placemarks.first! 
       completion(placemark) // set ViewController's properties 
      } else { 
       print("no data") 
      } 
      obj.dispatchGroup.leave() // ** ERROR ** 
     } 
    } 


} 

Appel de fonction du contrôleur principal de vue

dispatchGroup.enter() 
Geo.reverseG(coordinates, setValues) // completionHandler: setValues 

dispatchGroup.notify(queue: DispatchQueue.main) { 

    // call another function on completion 

} 
+0

Chaque appel 'leave' doit avoir un appel' enter' associé. Si vous appelez 'leave' sans avoir d'abord appelé' enter' Le problème ici est que vous appelez 'enter' sur un groupe, mais' reverseG' appelle 'leave' sur une autre instance de' ViewController'. Je suggère de passer le 'DispatchGroup' en tant que paramètre à votre méthode 'reverseG' ou, mieux,' reverseG' ne devrait pas quitter le groupe, mais plutôt mettre l'appel 'leave' dans le gestionnaire d'achèvement que' reserveG' appelle. – Rob

+0

Exactement, déjà fait cela et cela a fonctionné. Merci –

Répondre

0

Chaque appel leave doit avoir un appel enter associé. Si vous appelez leave sans avoir d'abord appelé enter, il va planter. Le problème ici est que vous appelez enter sur un groupe, mais reverseG appelle leave sur une autre instance de ViewController. Je suggère de passer le DispatchGroup en tant que paramètre à votre méthode reverseG. Ou, mieux, reverseG ne doit pas quitter le groupe, mais plutôt mettre l'appel leave dans le gestionnaire de fin que les appels reserveG.

dispatchGroup.enter() 
Geo.reverseG(coordinates) { placemark in 
    defer { dispatchGroup.leave() } 

    guard let placemark = placemark else { return } 

    // use placemark here, e.g. call `setValues` or whatever 
} 

dispatchGroup.notify(queue: DispatchQueue.main) { 
    // call another function on completion 
} 

Et

class Geo { 
    // var obj = ViewController() 

    static func reverseG(_ coordinates: CLLocation, completion: @escaping (CLPlacemark?) -> Void) { 
     let geoCoder = CLGeocoder() 
     geoCoder.reverseGeocodeLocation(coordinates) { placemarks, error in 
      if let error = error { 
       print("error: \(error.localizedDescription)") 
      } 
      completion(placemarks?.first) 

      // obj.dispatchGroup.leave() // ** ERROR ** 
     } 
    } 

} 

Cela permet de maintenir la logique DispatchGroup à un niveau de l'application, en gardant vos classes moins étroitement couplées (par exemple, le codeur Geo n'a pas besoin de savoir si le contrôleur de vue utilise l'envoi groupes ou non). Franchement, je ne comprends pas très bien pourquoi vous utilisez un groupe d'expédition s'il n'y a qu'un seul appel. Habituellement, vous placez ce que vous appelez dans le gestionnaire d'achèvement, ce qui simplifie encore le code. Vous n'utilisez généralement des groupes que si vous effectuez toute une série d'appels. (Vous avez peut-être simplement simplifié votre extrait de code alors que vous effectuez de nombreux appels.) Dans ce cas, un groupe de répartition peut avoir du sens, mais vous ne devriez pas faire de requêtes de géocodage simultanées, suggérant un modèle complètement différent. tout à fait.

+0

Je voulais juste inverser les fonctions géographiques dans une classe séparée et utiliser des repères dans la classe principale pour définir les propriétés (ne pas appeler une fonction de rappel). Le résultat de function1 est nécessaire pour function2 et function3 nécessite les résultats de f1 et f2 et j'utilise des gestionnaires d'achèvement pour ne définir que les propriétés de la classe principale. f1 définira la propriété à utiliser dans f2 et ainsi de suite –

+0

avec les gestionnaires de complétion, est-ce que c'est ... f1 (achèvement: f2 (achèvement: f3)) ?? si j'ai besoin de f3 pour utiliser les résultats de f1 et f2 –

+0

C'est difficile à dire sans plus de contexte. Étant donné que nous avons répondu à la question du groupe de dépanneurs ici, je pourrais vous suggérer de poster une nouvelle question dans un contexte plus large en nous montrant ce que vous faites. Si vous avez du code qui fonctionne et que vous voulez des commentaires sur la conception, http://codereview.stackexchange.com est peut-être un meilleur forum. Ou si cela ne fonctionne pas, allez-y et postez une question distincte sur Stack Exchange.De toute façon, n'hésitez pas à ajouter un commentaire avec le lien vers cette autre question. Mais nous nous sommes déjà trop éloignés de votre question de groupe d'expédition d'origine ... – Rob

0

Passé dispatchGroup comme paramètre avec appel de fonction et cela a fonctionné.

Geo.reverseG(coordinates, dispatchGroup, setValues)