Reputation: 31
I'm trying to dispatch some code to the main queue via GCD on iOS but even the most simple tests always fail. In the end It boiled down to this:
static const int TICK_INTERVAL = 1;
#pragma UIApplicationDelegate implementation
- (void) doTick
{
if (![NSThread isMainThread])
{
NSLog(@"Trying to dispatch . . .");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"test . . .");
});
}
}
- (void) startUpdate
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
timer_ = [NSTimer
scheduledTimerWithTimeInterval:TICK_INTERVAL
target:self
selector:@selector(backgroundUpdate)
userInfo:nil
repeats:NO
];
[[NSRunLoop currentRunLoop]
addTimer:timer_
forMode:NSRunLoopCommonModes
];
[[NSRunLoop currentRunLoop] run];
});
UIBackgroundTaskIdentifier back =
[[UIApplication sharedApplication]
beginBackgroundTaskWithExpirationHandler:^{
[self doTick];
[[UIApplication sharedApplication]
endBackgroundTask:back
];
}];
}
-(void)backgroundUpdate
{
[self doTick];
UIBackgroundTaskIdentifier back =
[[UIApplication sharedApplication]
beginBackgroundTaskWithExpirationHandler:^{
[self doTick];
[[UIApplication sharedApplication]
endBackgroundTask:back
];
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
timer_ = [NSTimer
scheduledTimerWithTimeInterval:TICK_INTERVAL
target:self
selector:@selector(backgroundUpdate)
userInfo:nil
repeats:NO
];
[[NSRunLoop currentRunLoop]
addTimer:timer_
forMode:NSRunLoopCommonModes
];
[[NSRunLoop currentRunLoop] run];
});
}
- (id) init
{
self = [super init];
[self startUpdate];
return self;
}
That's the my AppDelegate
.
I would expect the NSLog to be executed in the main thread to log the test text above, but nothing happens. dispatch_sync
code just waits forever and the breakpoint I placed inside the block is never reached.
I made sure that the code isn't executed in the main thread. Before testing with dispatch_sync
, I experimented with dispatch_async
in my app, the results being, of course, basically the same: nothing happens (without the blocking).
Interestingly enough, it just doesn't seem to work with the main queue, other queues (current queue, global queue) appear to work just fine.
I'm using Phonegap (Cordova) in my app, if that's of any significance.
Any ideas?
Thanks a lot!
Upvotes: 3
Views: 962
Reputation: 5589
You should never dispatch_sync
from a task executing on a queue to the same queue. This is guaranteed to deadlock on any serial queue like the main queue and is bad idea on concurrent queues. See Apple's Concurrency Programming Guide for more details. Since the application delegate's init method is run on the main thread, dispatch_sync
to the main queue causes a deadlock.
dispatch_async
to the main queue will work as long as you are running a normal NSRunLoop on the main thread. Of course your NSLog(@"test . . .")
may be executed substantially later than the completion of your application delegate's init method.
Upvotes: 4