Why does the print("2")
part never get called in the following code?
I'd think that the inner main.async
would push the block into the main loop's queue,
and then RunLoop.run
would execute it, but apparently that isn't what happens.
(It prints 1
, run
, run
, run
, etc.)
Also, if I remove the outer main.async
, and just directly run the code in that block
(still on the main queue, in viewDidLoad
of a new single-view app),
then the inner main.async
block does get executed (prints 1
, run
, 2
).
Why does this change make such a difference?
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
In your first example, the first async
blocks the main
serial queue until it returns from that outer async
call, something that won’t happen while x
is 1
. That inner GCD async
task (that updates x
to 2
) will never have a chance to run since that serial GCD queue is now blocked in that while
loop. The attempt to run
on the main run loop does not circumvent the rules/behavior of GCD serial queues. It only drains the run loop of events that have been added to it.
In your second example, you haven’t blocked the GCD main
queue, so when you hit run
, the dispatched block that updates x
to 2
does have a chance to run, letting it proceed.
Bottom line, don’t conflate the GCD main queue and the main run loop. Yes, they both use the main thread, but run loops can’t be used to circumvent the behavior of serial GCD queues.