我一直在尋找遊戲中心代碼示例,GKTapper,以及開發人員評論他的實現的一個部分對我沒有太大意義。代碼插入在下面。我不明白的是,爲什麼要調度一個修改主線程視圖控制器的塊不安全?塊和ViewController線程安全
他提到「如果在輔助隊列中執行的塊中引用了viewcontroller,那麼它可能會被釋放到主隊列之外,即使實際塊在主線程上被調度,情況也是如此。如果處理該版本的代碼位於主UI線程上(在主runloop上),那麼這種可能性如何?還是有一些Block/GCD,我沒有得到?
更讓人好奇的是他的解決方案甚至解決了這個問題。 「因爲」callDelegate「是訪問委託的唯一方法,所以我可以確保委託在我的任何塊回調中都不可見。」 (代表是這裏的視圖控制器)
有人能告訴我這件事嗎?我很新的塊和GCD,所以也許我缺少一些簡單的...
// NOTE: 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. This is true
// even if the actual block is scheduled on the main thread. In concrete terms, this code
// snippet is not safe, even though viewController is dispatching to the main queue:
//
// [object doSomethingWithCallback: ^()
// {
// dispatch_async(dispatch_get_main_queue(), ^(void)
// {
// [viewController doSomething];
// });
// }];
//
// UIKit view controllers should only be accessed on the main thread, so the snippet above may
// lead to subtle and hard to trace bugs. Many solutions to this problem exist. In this sample,
// I'm bottlenecking everything through "callDelegateOnMainThread" which calls "callDelegate".
// Because "callDelegate" is the only method to access the delegate, I can ensure that delegate
// is not visible in any of my block callbacks.
// *** Delegate in this case is a view controller. ***
- (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];
});
}
- (void) authenticateLocalUser
{
if([GKLocalPlayer localPlayer].authenticated == NO)
{
[[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error)
{
[self callDelegateOnMainThread: @selector(processGameCenterAuth:) withArg: NULL error: error];
}];
}
}
現在有道理啊,謝謝! – SunnyPianist 2011-04-03 10:16:34
事實上,我做了一些更多的研究之後,我有點困惑。根據我讀的內容,塊中的對象將被保留,例如在塊中引用的變量,「self」將被保留(因爲實例變量=自 - > ivar)。 在這種情況下,由於「viewcontroller」(或「委託」)是一個實例變量,「self」應該被塊保留嗎?如果這是真的,那麼塊不會獲得viewcontroller/delegate的最新值?指向該對象的「自我」指針仍然有效,自我委託應該仍然可以。 – SunnyPianist 2011-04-04 21:04:20