Swift 等待任务完成
如何使代码等待DispatchQueue中的任务完成?它需要任何CompletionHandler或其他什么吗Swift 等待任务完成,swift,multithreading,asynchronous,swift3,grand-central-dispatch,Swift,Multithreading,Asynchronous,Swift3,Grand Central Dispatch,如何使代码等待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 cont
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编写。使用调度组
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.
使用
DispatchGroup
s来实现这一点。您可以在组的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()
阻塞当前队列(在您的情况下可能是主队列),因此您必须在另一个队列上调度.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)")
最后一件事:如果要在任务使用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)")
}
假设您在主队列上调用此函数,这将导致死锁。@Shallow尽管如此。我想在另一个类中执行一个函数,但我想等待该函数完成,然后在当前类中继续执行,我如何处理它?尽管上面的示例将在主线程上阻塞,如前面的答案所示,在
DispatchQueue.global().async{}
中包装不会阻止主队列。我想在另一个类中执行函数,但我想等待完成该函数,然后在当前类中继续。我如何处理该问题?@saeedrahmotolahi:或者使用等待
方法(如果阻塞没有问题,即如果您不在主线程上)或者在调用类中提供一个完成处理程序或使用notify方法。为什么要调用组。在异步块之外输入?是否每个块都应该负责输入和离开组?@Bill等待直到输入和离开调用平衡。如果您输入输入在闭包中,wait
不会等待,因为尚未调用enter
,因此enter
和leave
调用的数量是平衡的(#enter==0,#leav==0).@rustyMagnet for tests这很可能不是正确的方法。请改用xctestextexpectation
s。请看,我尝试了所有这些方法,但在for循环中处理firebase调用时,没有一个有效
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)")
}