web-dev-qa-db-fra.com

Attendre la fin de la tâche

Comment faire attendre mon code jusqu'à la fin de la tâche dans DispatchQueue? At-il besoin de CompletionHandler ou de quelque chose?

func myFunction() {
    var a: Int?

    DispatchQueue.main.async {
        var b: Int = 3
        a = b
    }

    // wait until the task finishes, then print 

    print(a) // - this will contain nil, of course, because it
             // will execute before the code above

}

J'utilise Xcode 8.2 et j'écris dans Swift 3.

55
Bartosz Woźniak

Utilisez DispatchGroups pour y parvenir. Vous pouvez soit être averti lorsque les appels enter() et leave() du groupe sont équilibrés:

func myFunction() {
    var a: Int?

    let group = DispatchGroup()
    group.enter()

    DispatchQueue.main.async {
        a = 1
        group.leave()
    }

    // does not wait. But the code in notify() gets run 
    // after enter() and leave() calls are balanced

    group.notify(queue: .main) {
        print(a)
    }
}

ou vous pouvez attendre (et revenir):

func myFunction() -> Int? {
    var a: Int?

    let group = DispatchGroup()
    group.enter()

    // avoid deadlocks by not using .main queue here
    DispatchQueue.global(attributes: .qosDefault).async {
        a = 1
        group.leave()
    }

    // wait ...
    group.wait()

    // ... and return as soon as "a" has a value
    return a
}

Remarque : group.wait() bloque la file d'attente actuelle (probablement la file principale dans votre cas). Vous devez donc expédier.async sur une autre file d'attente (comme dans l'exemple de code ci-dessus) pour éviter un deadlock .

146
shallowThought

Dans Swift 3, le gestionnaire d'achèvement n'est pas nécessaire lorsque DispatchQueue termine une tâche. En outre, vous pouvez atteindre votre objectif de différentes manières

Une façon est la suivante.

    var a: Int?

    let queue = DispatchQueue(label: "com.app.queue")
    queue.sync {

        for  i in 0..<10 {

            print("Ⓜ️" , i)
            a = i
        }
    }

    print("After Queue \(a)")

Il attendra que la boucle se termine, mais dans ce cas, votre fil de discussion sera bloqué.

Vous pouvez aussi faire la même chose comme ça 

    let myGroup = DispatchGroup()
    myGroup.enter()
    //// Do your task

    myGroup.leave() //// When your task completes
     myGroup.notify(queue: DispatchQueue.main) {

        ////// do your remaining work
    }

Une dernière chose. Si vous souhaitez utiliser completionHandler à la fin de votre tâche avec DispatchQueue, vous pouvez utiliser DispatchWorkItem.

Voici un exemple d'utilisation de DispatchWorkItem

let workItem = DispatchWorkItem {
    // Do something
}

let queue = DispatchQueue.global()
queue.async {
    workItem.perform()
}
workItem.notify(queue: DispatchQueue.main) {
    // Here you can notify you Main thread
}
20
Usman Javed

Utiliser le groupe d'envoi 

   dispatchGroup.enter()
   FirstOperation(completion: { _ in
dispatchGroup.leave()
  })
    dispatchGroup.enter()
    SecondOperation(completion: { _ in
dispatchGroup.leave()
  })
   dispatchGroup.wait() //Waits here on this thread until the two operations complete executing.
1
Sahil Arora

Swift 4

Vous pouvez utiliser la fonction asynchrone pour ces situations. Lorsque vous utilisez DispatchGroup(), il peut arriver que deadlock se produise.

var a: Int?
@objc func myFunction(completion:@escaping (Bool) -> () ) {

    DispatchQueue.main.async {
        let b: Int = 3
        a = b
        completion(true)
    }

}

override func viewDidLoad() {
    super.viewDidLoad()

    myFunction { (status) in
        if status {
            print(self.a!)
        }
    }
}
0
codeByThey