1// NOTE: GameCenter does not guarantee that callback blocks will be execute on the main thread.
2// As such, your application needs to be very careful in how it handles references to view
3// controllers. If a view controller is referenced in a block that executes on a secondary queue,
4// that view controller may be released (and dealloc'd) outside the main queue. This is true
5// even if the actual block is scheduled on the main thread. In concrete terms, this code
6// snippet is not safe, even though viewController is dispatching to the main queue:
7// 8// [object doSomethingWithCallback: ^()
9// {
10// dispatch_async(dispatch_get_main_queue(), ^(void)
11// {
12// [viewController doSomething];
13// });
14// }];
15//16// UIKit view controllers should only be accessed on the main thread, so the snippet above may
17// lead to subtle and hard to trace bugs. Many solutions to this problem exist. In this sample,
18// I'm bottlenecking everything through "callDelegateOnMainThread" which calls "callDelegate".
19// Because "callDelegate" is the only method to access the delegate, I can ensure that delegate
20// is not visible in any of my block callbacks.2122 - (void) callDelegate: (SEL) selector withArg: (id) arg error: (NSError*) err
23{
24 assert([NSThread isMainThread]);
25if([delegate respondsToSelector: selector])
26 {
27if(arg != NULL)
28 {
29 [delegate performSelector: selector withObject: arg withObject: err];
30 }
31else32 {
33 [delegate performSelector: selector withObject: err];
34 }
35 }
36else37 {
38 NSLog(@"Missed Method");
39 }
40}
4142 - (void) callDelegateOnMainThread: (SEL) selector withArg: (id) arg error: (NSError*) err
43{
44 dispatch_async(dispatch_get_main_queue(), ^(void)
45 {
46 [self callDelegate: selector withArg: arg error: err];
47 });
48}
4950 - (void) authenticateLocalUser
51{
52if([GKLocalPlayer localPlayer].authenticated == NO)
53 {
54 [[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error)
55 {
56 [self callDelegateOnMainThread: @selector(processGameCenterAuth:) withArg: NULL error: error];
57 }];
58 }
59 }