I have some calculation work on background thread, after that I need to update the transform of some calayer, I try use
dispatch_async(dispatch_get_main_queue(), ^{calayer.transform = newTransform});
and
CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^(void) {calayer.transform = newTransform});
I just thought they are the same, but I found the calayer worked much smooth(maybe?) when using dispatch_async. what is the different about these two functions?
The primary difference here is that CFRunLoopPerformBlock
allows you to specify specific run loop modes in which to execute the block, whereas dispatch_async(dispatch_get_main_queue(),...)
is going to execute in common modes only. Perhaps more apropos to the performance issue you're seeing, CFRunLoopPerformBlock
does not wake up the main thread. From the documentation for CFRunLoopPerformBlock
:
This method enqueues the block only and does not automatically wake up the specified run loop. Therefore, execution of the block occurs the next time the run loop wakes up to handle another input source. If you want the work performed right away, you must explicitly wake up that thread using the CFRunLoopWakeUp function.
In practice, this will usually mean that your block wont be executed until the time the run loop wakes up (i.e. user event occurs, timer fires, run loop source fires, mach message is received, etc.) GCD is not, by design, a run-loop based API; the relationship between the main queue and the main thread run loop is, effectively, an implementation detail. I would expect that implementation to wake up the run loop itself if that were necessary for the main queue to be serviced.
Absent information to the contrary, I strongly suspect this is the source of the difference in performance. I would expect the performance to be similar if you added a call to CFRunLoopWakeUp
immediately after your call to CFRunLoopPerformBlock
.