等待任务完成

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


}

我用的是 Xcode 8.2,用的是 Swift 3。

161449 次浏览

使用调度组

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.

如果需要向调用者隐藏 myFunction的异步特性,可以使用 DispatchGroup来实现。否则,使用完成块。找到下面两个样本。


DispatchGroup 示例

当组的 enter()leave()调用平衡时,您可以得到通知:

func myFunction() {
var a = 0


let group = DispatchGroup()
group.enter()


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


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


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

或者你可以等:

func myFunction() {
var a = 0


let group = DispatchGroup()
group.enter()


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


// wait ...
group.wait()
    

print(a) // you could also `return a` here
}

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


完成整块样本

func myFunction(completion: @escaping (Int)->()) {
var a = 0


DispatchQueue.main.async {
let b: Int = 1
a = b
completion(a) // call completion after you have the result
}
}


// on caller side:
myFunction { result in
print("result: \(result)")
}

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

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

不知为何,上面的 patchGroup enter ()和 leave ()命令对我的情况不起作用。

在后台线程的 while 循环中使用 sleep (5)对我来说很有用。离开这里是为了帮助其他人而且不会影响到我的其他线索。

在 Swift 5.5 + 中,您可以利用 Swift 并发性,它允许从发送到主线程的闭包返回一个值

func myFunction() async {
var a : Int?


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


print(a)
}


Task {
await myFunction()
}