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: Roland King <email@hidden>
- Date: Sat, 06 Sep 2014 06:18:41 +0800
>
> Why not? I assume Jonathan's -shouldIAccept: is running a nested event loop for the modal panel, since it doesn't return till the user dismisses it.
>
> (Whether it's a dispatch_sync or a dispatch_async doesn't matter; the main thread will be blocked for as long as the block takes to run.)
>
> I still think the problem is that you're blocking the dispatch-queue's thread for a long time. Try pausing the app while the dialog is up and looking at what the various threads are doing.
>
> —Jens
> _______________________________________________
Don’t think it’s the dispatch thread, they are quite capable of being out of action for ages.
It is however quite easy to show this happening. Stick the code at the bottom in the AppDelegate of a fresh OSX Cocoa app from the template, drag out 3 buttons and hook them up to pushOne . . etc.
Hit button one and it just pops up the open panel from the button click - works fine
Hit button two and it dispatches sync onto the main thread and does the same thing, it’s terrible, scrolling doesn’t work properly .. mess
Hit button three and it does a perform selector on the main thread with the same code and waits for it and that .. works properly
The stack traces are very similar, after the runModal they’re the same, as you’d expect. So the only difference between the the cases is that if you performSelector the original main runloop is in .._IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION .. and from there it runs the model dialog.
In the case of dispatching onto the main dispatch queue the runloop was .._SERVICING_THE_MAIN_DISPATCH_QUEUE.. when it goes into the runModal code.
I can only think that ‘state’ of the main runloop when runModal is called makes a difference and being in the ‘haven’t finished dispatching main dispatch events’ state causes it to have trouble servicing the runModal runloop. Not that it’s doing anything, the whole machine is idle, but they are likely two quite different states/stages of the runloop cycle.
Rarely do I suggest performSelector: but it happens to work here. I’d love to know more about why dispatch doesn’t work so well however.
#import "AppDelegate.h"
@interface AppDelegate ()
-(IBAction)pushOne:(id)sender;
-(IBAction)pushTwo:(id)sender;
-(IBAction)pushThree:(id)sender;
@end
static BOOL flag1 = NO;
static BOOL flag2 = NO;
@implementation AppDelegate
-(void)doNothing
{
int count = 0;
while( count < 100 )
{
[ NSThread sleepForTimeInterval:1 ];
NSLog( @"%d", count );
count++;
if( flag1 )
{
flag1 = NO;
dispatch_sync( dispatch_get_main_queue(), ^{
[ self doTheOpenPanelThing ];
} );
}
if( flag2 )
{
flag2 = NO;
[ self performSelectorOnMainThread:@selector( doTheOpenPanelThing ) withObject:nil waitUntilDone:YES ];
}
}
}
-(void)doTheOpenPanelThing
{
NSOpenPanel *panel = [ NSOpenPanel openPanel ];
[ panel runModal ];
}
-(void)pushOne:(id)sender
{
NSLog( @"One Pushed" );
[ self doTheOpenPanelThing ];
}
-(void)pushTwo:(id)sender
{
NSLog( @"Two Pushed" );
flag1 = YES;
}
-(void)pushThree:(id)sender
{
NSLog( @"Three Pushed" );
flag2 = YES;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[ self doNothing ];
} );
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
@end
_______________________________________________
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