我有一个工作的应用程序,我正在把它转换成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公约?


当前回答

警告=> "在块内捕获自我可能导致保留循环"

当你在一个被self强保留的块中引用self或它的属性时,它会显示上述警告。

为了避免这种情况,我们必须将其设为一周参考

__weak typeof(self) weakSelf = self;

所以不用

blockname=^{
    self.PROPERTY =something;
}

我们应该使用

blockname=^{
    weakSelf.PROPERTY =something;
}

注意:retain循环通常发生在两个对象相互引用时,它们的引用计数都为1,并且它们的delloc方法永远不会被调用。

其他回答

警告=> "在块内捕获自我可能导致保留循环"

当你在一个被self强保留的块中引用self或它的属性时,它会显示上述警告。

为了避免这种情况,我们必须将其设为一周参考

__weak typeof(self) weakSelf = self;

所以不用

blockname=^{
    self.PROPERTY =something;
}

我们应该使用

blockname=^{
    weakSelf.PROPERTY =something;
}

注意:retain循环通常发生在两个对象相互引用时,它们的引用计数都为1,并且它们的delloc方法永远不会被调用。

当你确信这个循环在未来会被打破时,你也可以选择抑制警告:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"

self.progressBlock = ^(CGFloat percentComplete) {
    [self.delegate processingWithProgress:percentComplete];
}

#pragma clang diagnostic pop

这样你就不必在__weak, self aliasing和显式的ivar前缀上瞎折腾了。

对于一个常见的解决方案,我在预编译头中定义了这些。避免捕获,并通过避免使用id启用编译器帮助

#define BlockWeakObject(o) __typeof(o) __weak
#define BlockWeakSelf BlockWeakObject(self)

然后在代码中你可以这样做:

BlockWeakSelf weakSelf = self;
self.dataProcessor.completion = ^{
    [weakSelf.delegate myAPIDidFinish:weakSelf];
    weakSelf.dataProcessor = nil;
};

结合其他一些答案,这是我现在在块中使用的类型化弱自我:

__typeof(self) __weak welf = self;

我将其设置为在方法/函数中带有“welf”完成前缀的XCode代码片段,在只输入“we”后命中。

新的方法是使用@weakify和@ stronggify marco

@weakify(self);
[self methodThatTakesABlock:^ {
    @strongify(self);
    [self doSomething];
}];

更多关于@Weakify @ stronggify马可的信息