也许有很多更好的方法可以用一种完全不同的方法来解决这个问题,但是我很幽默。我想知道这种确切情况。
在这里,我有两个功能,doSomething
和doSomethingElse
。它们是从doEverything()
调用的,并且都返回会触发异步的completeBlock。
目标是在这两个异步调用均完成后立即调用everythingDone()
。如我所说,可能有更好的解决方法,但我想知道这种精确的逻辑会发生什么。
在两个完成中,我检查两个完成是否都已完成,然后调用everythingDone
。
func doSomething(completion:((Int)->())?){
DispatchQueue.global(qos: .background).async {
completion?(123)
}
}
func doSomethingElse(completion:((String)->())?){
DispatchQueue.global(qos: .background).async {
completion?("Test")
}
}
func doEverything(){
var values:[Any] = []
var somethingDone:Bool = false
var somethingElseDone:Bool = false
doSomething { (value) in
DispatchQueue.main.async {
values.append(value)
somethingDone = true
if somethingDone && somethingElseDone{
self.everythingDone(values: values)
}
}
}
doSomethingElse { (value) in
DispatchQueue.main.async {
values.append(value)
somethingElseDone = true
if somethingDone && somethingElseDone{
self.everythingDone(values: values)
}
}
}
}
func everythingDone(values:[Any]){
print("Everything done: ", values)
}
everythingDone
会发生两次吗?事件的顺序是否有可能导致此情况:
somethingDone=true
somethingElseDone = true
这会发生吗? main.asyc调用可以“交织”吗?
答案 0 :(得分:5)
简短答案:
没有。 everythingDone
不能被调用两次。
详细答案:
主要的 queue (DispatchQueue.main
)是 serial queue ,这意味着任务将一个接一个地完成,第二个DispatchQueue.main.async
关闭将完成等待,直到第一个完成任务。
一些示范:
想象以下代码:
DispatchQueue.global(qos: .background).async {
DispatchQueue.main.async {
//Closure A
for i in 0..<10 {
print("a\(i)")
}
}
}
DispatchQueue.global(qos: .background).async {
DispatchQueue.main.async {
//Closure B
for i in 0..<10 {
print("b\(i)")
}
}
}
如果运行此代码,则在控制台中将看到以下结果:
a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 00 11 b2 b3 44 55 66 7 88 b9
如您所见,首先,它运行并完成Close A
内的代码,只有在它开始并完成Closure B
内的代码之后。
但是,如果我们稍微修改一下代码(通过将闭包直接移到全局队列:
DispatchQueue.global(qos: .background).async {
//Closure A
for i in 0..<10 {
print("a\(i)")
}
}
DispatchQueue.global(qos: .background).async {
//Closure B
for i in 0..<10 {
print("b\(i)")
}
}
结果如下:
b0 00 11 b2 b3 44 55 a1 66 a2 7 a3 88 a4 a5 a6 a7 a8 a9 b9
在这里您可以看到顺序已中断,甚至是不可预测的,并且每次执行时都可能更改。
这是因为DispatchQueue.global(qos: .background)
是并发队列,因此任务将同时执行,并且将在意外的时间表上完成。
因此,一旦您的封包进入串行队列(在您的情况下为主队列),答案为否,否则,答案为是。