Xcode 4.6 中针对Game Center认证的ARC警告

10

这是一个新的编译器警告,在我更新XCode到4.6之后才出现。我的代码直接从苹果的文档中提取(顺便说一句,这是我的iOS 6代码)。

GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];

localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error) {
    [self setLastError:error];
    if(localPlayer.authenticated){

警告--在此块中强引用'localPlayer'很可能会导致保留周期

2个回答

25
问题在于localPlayer对象对自身保持了强引用——当localPlayer被“捕获”以在authenticateHandler块中使用时,它会被保留(当Objective-C对象在块中被引用时,ARC编译器会为您调用retain)。现在,即使所有对localPlayer的其他引用都不存在了,它仍然具有1个保留计数,因此内存永远不会被释放。这就是编译器给出警告的原因。
使用弱引用来引用它,例如:
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];

__weak GKLocalPlayer *blockLocalPlayer = localPlayer;
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error) {
    [self setLastError:error];
    if (blockLocalPlayer.authenticated) {
        ...

考虑到认证处理程序和本地玩家的生命周期紧密相关(即当本地玩家被释放时,认证处理程序也会被释放),因此在认证处理程序内部不需要保持强引用。 在使用Xcode 4.6时,这不再产生您提到的警告。


1
谢谢!我现在对于块保留循环有更深的理解了。这非常完美。 - mevdev
2
您也可以不创建localPlayer变量,始终使用[GKLocalPlayer localPlayer],这样就不会保留任何引用。 - tothemario

1
编译器只是帮助你解决了已经存在的问题,只是之前它不知道而已。
你可以在这里阅读有关保留循环的信息:http://www.cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html 基本上,你只需要将你的代码更改为类似以下的内容:
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];

__weak MyViewController *blockSelf = self;
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error) {
    [blockSelf setLastError:error];
    if(localPlayer.authenticated){

这对我似乎不起作用。 我能否只是弱引用localPlayer?我正在我的AppDelegate中进行身份验证,因此没有相应的viewController。 - mevdev
是的,我看错了你的问题,并认为它在抱怨捕获自身。使用Chris McGrath发布的内容。 - Eric Reid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接