iOS RunLoop 和 DispatchQueue.main.async
iOS RunLoop and DispatchQueue.main.async
为什么 print("2")
部分在下面的代码中永远不会被调用?
我认为内部 main.async
会将块推入主循环的队列中,
然后 RunLoop.run
会执行它,但显然情况并非如此。
(打印 1
、run
、run
、run
等)
此外,如果我删除外部 main.async
,直接 运行 该块中的代码
(仍在主队列中,在新的单视图应用程序的 viewDidLoad
中),
然后内部 main.async
块确实得到执行(打印 1
、run
、2
)。
为什么这一变化会产生如此大的不同?
var x = -1
DispatchQueue.main.async { // comment out this line for question #2
print("1")
x = 1
DispatchQueue.main.async {
print("2")
x = 2
}
while x == 1 {
print("run")
RunLoop.main.run(mode: .default, before: Date() + 1)
}
} // comment out this line for question #2
在您的第一个示例中,第一个 async
阻塞 main
串行队列,直到它 returns 来自外部 async
调用,而这不会发生x
是 1
。内部 GCD async
任务(将 x
更新为 2
)将永远没有机会 运行 因为串行 GCD 队列现在在 while
中被阻塞环形。在主 运行 循环中尝试 run
并不能绕过 GCD 串行队列的 rules/behavior。它只会耗尽已添加到其中的 运行 事件循环。
在你的第二个例子中,你没有阻塞 GCD main
队列,所以当你点击 run
时,调度块将 x
更新为 2
确实有机会运行,让它继续。
底线,不要混淆 GCD 主队列和主 运行 循环。是的,它们都使用主线程,但是运行循环不能用来规避串行GCD队列的行为。
为什么 print("2")
部分在下面的代码中永远不会被调用?
我认为内部 main.async
会将块推入主循环的队列中,
然后 RunLoop.run
会执行它,但显然情况并非如此。
(打印 1
、run
、run
、run
等)
此外,如果我删除外部 main.async
,直接 运行 该块中的代码
(仍在主队列中,在新的单视图应用程序的 viewDidLoad
中),
然后内部 main.async
块确实得到执行(打印 1
、run
、2
)。
为什么这一变化会产生如此大的不同?
var x = -1
DispatchQueue.main.async { // comment out this line for question #2
print("1")
x = 1
DispatchQueue.main.async {
print("2")
x = 2
}
while x == 1 {
print("run")
RunLoop.main.run(mode: .default, before: Date() + 1)
}
} // comment out this line for question #2
在您的第一个示例中,第一个 async
阻塞 main
串行队列,直到它 returns 来自外部 async
调用,而这不会发生x
是 1
。内部 GCD async
任务(将 x
更新为 2
)将永远没有机会 运行 因为串行 GCD 队列现在在 while
中被阻塞环形。在主 运行 循环中尝试 run
并不能绕过 GCD 串行队列的 rules/behavior。它只会耗尽已添加到其中的 运行 事件循环。
在你的第二个例子中,你没有阻塞 GCD main
队列,所以当你点击 run
时,调度块将 x
更新为 2
确实有机会运行,让它继续。
底线,不要混淆 GCD 主队列和主 运行 循环。是的,它们都使用主线程,但是运行循环不能用来规避串行GCD队列的行为。