我有一个工作的应用程序,我正在把它转换成Xcode 4.2中的ARC。预检查警告之一涉及在块中强烈捕获self,从而导致保留循环。我做了一个简单的代码示例来说明这个问题。我相信我理解这意味着什么,但我不确定实现这类场景的“正确”或推荐方法。
self是MyAPI类的实例
下面的代码经过简化,只显示与我的问题相关的对象和块的交互
假设MyAPI从远程数据源获取数据,MyDataProcessor处理该数据并产生输出
处理器配置了块来通信进程和状态
代码示例:
// code sample
self.delegate = aDelegate;
self.dataProcessor = [[MyDataProcessor alloc] init];
self.dataProcessor.progress = ^(CGFloat percentComplete) {
[self.delegate myAPI:self isProcessingWithProgress:percentComplete];
};
self.dataProcessor.completion = ^{
[self.delegate myAPIDidFinish:self];
self.dataProcessor = nil;
};
// start the processor - processing happens asynchronously and the processor is released in the completion block
[self.dataProcessor startProcessing];
问题:我做了什么“错误”和/或这应该如何修改,以符合ARC公约?
如果你确定你的代码不会创建一个保留循环,或者这个循环稍后会被打破,那么最简单的方法是:
// code sample
self.delegate = aDelegate;
self.dataProcessor = [[MyDataProcessor alloc] init];
[self dataProcessor].progress = ^(CGFloat percentComplete) {
[self.delegate myAPI:self isProcessingWithProgress:percentComplete];
};
[self dataProcessor].completion = ^{
[self.delegate myAPIDidFinish:self];
self.dataProcessor = nil;
};
// start the processor - processing happens asynchronously and the processor is released in the completion block
[self.dataProcessor startProcessing];
这样做的原因是Xcode的分析考虑到了属性的点访问,因此
x.y.z = ^{ block that retains x}
被视为保留x的y(在赋值的左边)和y的x(在右边),方法调用不受相同的分析,即使当它们是属性访问方法调用,等价于点访问,即使当这些属性访问方法是编译器生成的,那么在
[x y].z = ^{ block that retains x}
只有右侧被视为创建保留(通过y (x)),并且不会生成保留周期警告。
警告=> "在块内捕获自我可能导致保留循环"
当你在一个被self强保留的块中引用self或它的属性时,它会显示上述警告。
为了避免这种情况,我们必须将其设为一周参考
__weak typeof(self) weakSelf = self;
所以不用
blockname=^{
self.PROPERTY =something;
}
我们应该使用
blockname=^{
weakSelf.PROPERTY =something;
}
注意:retain循环通常发生在两个对象相互引用时,它们的引用计数都为1,并且它们的delloc方法永远不会被调用。