等到任务完成

Bar*_*iak 80 multithreading asynchronous grand-central-dispatch swift swift3

我怎么能让我的代码等到DispatchQueue中的任务完成?它需要任何CompletionHandler或其他东西吗?

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

}
Run Code Online (Sandbox Code Playgroud)

我正在使用Xcode 8.2并在Swift 3中编写.

sha*_*ght 187

使用DispatchGroups来实现这一目标.您可以在群组enter()leave()呼叫平衡时收到通知:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

或者你可以等待(并返回):

func myFunction() {
    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()

    print(a) // you could also `return a` here
}
Run Code Online (Sandbox Code Playgroud)

注意:group.wait()阻塞当前队列(可能是您的主要队列),因此您必须在另一个队列上调度.async(如上面的示例代码中所示)以避免死锁.

  • @Bill`wait`等待,直到`enter`和`leave`调用平衡.如果你把`enter`放在闭包中,`wait`就不会等了,因为`enter`还没有被调用,因此`enter`和`leave`的数量调用_are_ balanced(#enter == 0,#leav = = 0). (3认同)
  • @SaeedRahmatolahi:要么使用`wait`方法(如果没有问题要阻止,即如果你不在主线程上)或提供完成处理程序或在你的调用类中使用notify方法. (2认同)

Usm*_*ved 24

在Swift 3中,DispatchQueue完成一个任务时不需要完成处理程序.此外,您可以通过不同方式实现目标

一种方法是这样.

    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)")
Run Code Online (Sandbox Code Playgroud)

它将等到循环结束,但在这种情况下,您的邮件线程将阻止.

你也可以这样做

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

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

        ////// do your remaining work
    }
Run Code Online (Sandbox Code Playgroud)

最后一件事.如果要在任务使用DispatchQueue完成时使用completionHandler,则可以使用DispatchWorkItem.

这是一个如何使用的例子 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
}
Run Code Online (Sandbox Code Playgroud)

  • 我尝试了所有这些,但在尝试处理 for 循环中的 firebase 调用时没有一个起作用 (2认同)
  • 该解决方案虽然视觉上很优雅,但无法处理超出您控制范围的代码异步运行的实际场景(即第一条评论中指出的 firebase 回调)。您将需要`.wait()`来处理更复杂的情况。 (2认同)

小智 11

Swift 5 版本的解决方案

func myCriticalFunction() {
    var value1: String?
    var value2: String?

    let group = DispatchGroup()


    group.enter()
    //async operation 1
    DispatchQueue.global(qos: .default).async { 
        // Network calls or some other async task
        value1 = //out of async task
        group.leave()
    }


    group.enter()
    //async operation 2
    DispatchQueue.global(qos: .default).async {
        // Network calls or some other async task
        value2 = //out of async task
        group.leave()
    }

    
    group.wait()

    print("Value1 \(value1) , Value2 \(value2)") 
}
Run Code Online (Sandbox Code Playgroud)