Mar*_*eau 12 objective-c nsoperation grand-central-dispatch objective-c-blocks automatic-ref-counting
我将一些NSOperation代码转换为ARC时遇到了困难.我的操作对象使用完成块,该完成块又包含一个GCD块,用于更新主线程上的UI.因为我从自己的完成块中引用了我的操作对象,所以我使用__weak指针来避免内存泄漏.但是,在我的代码运行时,指针已经设置为nil.
我把它缩小到这个代码示例.谁知道我哪里出错了,以及正确的方法来实现这一目标?
NSOperationSubclass *operation = [[NSOperationSubclass alloc] init];
__weak NSOperationSubclass *weakOperation = operation;
[operation setCompletionBlock:^{
dispatch_async( dispatch_get_main_queue(), ^{
// fails the check
NSAssert( weakOperation != nil, @"pointer is nil" );
...
});
}];
Run Code Online (Sandbox Code Playgroud)
eof*_*ter 16
另一种选择是:
NSOperationSubclass *operation = [[NSOperationSubclass alloc] init];
__weak NSOperationSubclass *weakOperation = operation;
[operation setCompletionBlock:^{
NSOperationSubclass *strongOperation = weakOperation;
dispatch_async(dispatch_get_main_queue(), ^{
assert(strongOperation != nil);
...
});
}];
[operationQueue addOperation:operation];
Run Code Online (Sandbox Code Playgroud)
我假设您还将操作对象添加到NSOperationQueue.在这种情况下,队列保留操作.它可能在执行完成块期间保留它(尽管我还没有找到关于完成块的官方确认).
但是在完成块内部会创建另一个块.该块将在稍后的某个时间点运行,可能在NSOperations的完成块运行结束之后.当发生这种情况时,operation将由队列释放weakOperation并将nil.但是如果我们从操作的完成块创建另一个对同一对象的强引用,我们将确保operation在第二个块运行时存在,并避免保留周期,因为我们不operation通过块捕获变量.
Apple在转换为ARC发行说明中提供了此示例,请参阅" 使用生命周期限定符以避免强引用周期"部分中的最后一个代码段.
lee*_*ker 10
我不确定这一点,但正确的方法是将__block添加到有问题的变量中,然后在块的末尾将其设置为nil以确保它被释放.看到这个问题.
您的新代码如下所示:
NSOperationSubclass *operation = [[NSOperationSubclass alloc] init];
__block NSOperationSubclass *weakOperation = operation;
[operation setCompletionBlock:^{
dispatch_async( dispatch_get_main_queue(), ^{
// fails the check
NSAssert( weakOperation != nil, @"pointer is nil" );
...
weakOperation = nil;
});
}];
Run Code Online (Sandbox Code Playgroud)
接受的答案是正确的。但从 iOS 8 / Mac OS 10.10 开始无需弱化操作:
NSOperation 文档中关于 @completionBlock 的引用:
在 iOS 8 及更高版本和 OS X v10.10 及更高版本中,在完成块开始执行后此属性设置为 nil。
另请参阅皮特·斯坦伯格的这条推文。
| 归档时间: |
|
| 查看次数: |
5702 次 |
| 最近记录: |