I've read a lot about GameCenter from various sources...particularly Apple's documentation as well as some Apress books about implementing GameCenter multiplayer but I cannot find a clear answer as to whether or not I can trust callbacks such as matchmakerViewController:didFindMatch or match:didReceiveData:fromPlayer (just to name a couple of examples) to always come on the main thread.
Occasionally in Apple's documentation, they explicitly say that a call will always be on the main thread but they're not consistent about being clear for each function.
The Apress books tend to be completely paranoid about the thread so they're using dispatch_async to make sure it ends up on the main thread.
My question is simply...can I trust that unless Apple says otherwise, the calls will be on the main thread or do i need to be as paranoid as the Apress books.
(Please no answers like 'just be paranoid everywhere and don't worry about it')
I have been looking into the same thing and the most explicit comment from Apple I can find about this issue is in the comments at the head of the GameCenterManager.m file within the GKTapper sample app they provide (https://developer.apple.com/library/ios/samplecode/gktapper/Listings/Classes_GameCenterManager_m.html):
“GameCenter does not guarantee that callback blocks will be execute on the main thread. As such, your application needs to be very careful in how it handles references to view controllers. If a view controller is referenced in a block that executes on a secondary queue, that view controller may be released (and dealloc'd) outside the main queue.”
The solution suggested (and implemented in the sample) is shown below.
Although GameKit has gone through a couple of new releases since the code was released, I haven’t seen anything stating that that this is no longer a problem, so I will be implementing this solution in my own code.
- (void) callDelegate: (SEL) selector withArg: (id) arg error: (NSError*) err
{
assert([NSThread isMainThread]);
if([delegate respondsToSelector: selector])
{
if(arg != NULL)
{
[delegate performSelector: selector withObject: arg withObject: err];
}
else
{
[delegate performSelector: selector withObject: err];
}
}
else
{
NSLog(@"Missed Method");
}
}
- (void) callDelegateOnMainThread: (SEL) selector withArg: (id) arg error: (NSError*) err
{
dispatch_async(dispatch_get_main_queue(), ^(void)
{
[self callDelegate: selector withArg: arg error: err];
});
}
I would strongly suggest downloading the GKTapper sample app and playing around with it to see how it works before diving in and implementing your own GameKit solution.