Re: dispatch_sync(dispatch_get_main_queue() UI weirdness
Re: dispatch_sync(dispatch_get_main_queue() UI weirdness
- Subject: Re: dispatch_sync(dispatch_get_main_queue() UI weirdness
- From: Ken Thomases <email@hidden>
- Date: Fri, 05 Sep 2014 23:50:15 -0500
On Sep 5, 2014, at 1:44 PM, Jonathan Guy <email@hidden> wrote:
> This is for MacOS not iOS.
>
> If your running code on a GCD queue
>
> dispatch_sync(dispatch_get_main_queue(), ^{
> //do UI stuff
> });
>
> is pretty much the way to do UI stuff on the main thread/queue which seems to work well for iOS. MacOS seems to be a different story. Try this for a simple example
>
> - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
> {
> dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
>
> // So my app is doing some background stuff
> // and I need a file from the user so
>
> // code blah blah code
>
> dispatch_sync(dispatch_get_main_queue(), ^{
> NSOpenPanel *op = [NSOpenPanel openPanel];
>
> [op runModal];
> });
>
> // resume code blah blah code
> });
> }
> when the NSOpenPanel opens all kinds of weirdness is going on. The scroll views scroll very erratically if at all and the directories don't list properly. I'm just using the NSOpenPanel here as an example, this also happens with any view that contains a scroll view (so I've tested so far). Is this a bug? Are others seeing this or is it just me and is there another preferred way of doing this?
This is an issue I have encountered before. NSOpenPanel does certain operations, like loading the icons for files, asynchronously in the background. Then, when those background operations are completed, it updates the dialog by submitting tasks to the main dispatch queue. However, the main dispatch queue is a serial queue. It is currently monopolized by your block which has called into -runModal. It won't execute any more tasks until that block completes. So, the panel's asynchronous background work can't complete.
It doesn't matter whether your block was submitted to the main queue with dispatch_sync() or dispatch_async(). I agree with others that, in general, you should structure your code to submit blocks asynchronously whenever possible (regardless of which queue you're submitting them to). Similarly, you should avoid blocking whenever possible, preferring asynchronous, callback-based APIs. However, none of that affects this issue.
It's simply the case that NSOpenPanel can't be run, directly or indirectly, from a block submitted to the main dispatch queue.
You can use -performSelectorOnMainThread:… just fine. That is not a serialized mechanism. If the run loop is in the middle of performing a selector and is re-entered (as for the modal event loop run for a modal dialog), it can still run other submitted dispatch tasks and performed selectors.
Because of this, I consider it a bug that NSOpenPanel uses GCD rather than -performSelectorOnMainThread:… or a similar non-serial mechanism for getting its updates back to the main thread. And everybody else using GCD should carefully consider this issue in their own designs. (Note that it also doesn't matter whether NSOpenPanel has submitted its updates from the background to the main thread synchronously or asynchronously. If it submits it asynchronously, the background thread can continue, but it will just have an opportunity to queue more things on the main queue that will never get run. If it submits synchronously, it will block, but that's just as well.)
Frankly, Apple should add a new dispatch queue that is serviced by the main thread but which is technically not a serial queue. It won't be quite a fully concurrent queue, since it would only be serviced by one thread, but it would allow blocks to be serviced in a nested fashion if one of those blocks runs the run loop. Basically, it would work just like -performSelectorOnMainThread:… does.
Regards,
Ken
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden