繁体   English   中英

"等到任务完成"

[英]Waiting until the task finishes

如何让我的代码等到 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

}

使用DispatchGroup来实现这一点。 您可以在组的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)
    }
}

或者你可以等待:

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
}

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

在 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)")

它将等到循环完成,但在这种情况下,您的主线程将阻塞。

你也可以做同样的事情:

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

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

        ////// do your remaining work
    }

最后一件事:如果您想在使用 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
}

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)") 
}

使用调度组

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.

斯威夫特 4

您可以在这些情况下使用异步函数。 当您使用DispatchGroup() ,有时可能会发生死锁

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!)
        }
    }
}

不知何故,上面的 dispatchGroup enter() 和 leave() 命令不适用于我的情况。

不过,在后台线程的 while 循环中使用 sleep(5) 对我有用。 离开这里以防它帮助其他人并且它没有干扰我的其他线程。

在 Swift 5.5+ 中,您可以利用 Swift Concurrency,它允许从分派到主线程的闭包中返回一个值

func myFunction() async {
    var a : Int?

    a = await MainActor.run {
        let b = 3
        return b
    }

    print(a)
}

Task {
    await myFunction()
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM