ARC,块和保留周期

时间:2011-10-13 22:15:14

标签: iphone ios ios5 automatic-ref-counting afnetworking

使用ARC。处理面向4.0和5.0的iOS项目。

遇到与块相关的问题,ARC以及从块外部引用对象。这是一些代码:

 __block AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
   [operation setCompletionBlock:^ {
       if ([operation isCancelled]) {
           return;
       }

... do stuff ...

operation = nil;
}];

在这种情况下,编译器会发出一个警告,即在块中使用“operation”将导致保留周期。在ARC下,__block现在保留变量。

如果我添加__unsafe_unretained,编译器会立即释放该对象,所以很明显这不起作用。

我的目标是4.0,所以我不能使用__weak。

我尝试过这样的事情:

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
__block __unsafe_unretained AFHTTPRequestOperation *weakOperation = operation;

但是虽然weakOperation不是nil,但是当在块内时,它们的属性都不会填充。

鉴于上面列出的项目限制,处理这种情况的最佳方法是什么?

2 个答案:

答案 0 :(得分:23)

假设进度保证,保留周期可能正是您想要的。您明确地在块结束时中断了保留周期,因此它不是永久保留周期:当调用块时,周期就会中断。

但是,如果您还有其他操作可以保留操作,则可以将引用存储到__weak__unsafe_unretained变量中,然后在块中使用该变量。没有必要__block - 限定变量,除非由于某种原因需要在块中更改变量的绑定;因为你没有剩余的保留周期,所以你不需要为弱变量分配任何东西。

答案 1 :(得分:1)

这似乎是康拉德斯托尔在Blocks, Operations, and Retain Cycles中描述的问题,但他的写作错过了几个要点:

  • __block看起来像苹果推荐的避免在MRC模式下强烈引用捕获变量的方法,但在ARC模式下完全没有必要。在这种情况下,在ARC模式下完全没有必要;在MRC模式下它也是不必要的,尽管更轻量级的解决方法更加冗长:void * unretainedOperation = operation; ... ^{ AFHTTPRequestOperation * op = unretainedOperation; }
  • 在ARC模式下,您既需要强引用(因此可以将其添加到队列中),也需要弱/ unsafe_unretained引用

最简单的解决方案如下:

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
AFHTTPRequestOperation * __unsafe_unretained unretainedOperation = operation;

[operation setCompletionBlock:^ {
  if ([unretainedOperation isCancelled]) {
    return;
  }
  ... do stuff ...
}];

即使你打破了引用周期,也没有理由让Block首先保留AFHTTPRequestOperation(假设操作在完成处理程序完成之前保持活动状态,这并不总是保证但通常是真的,如果在调用堆栈的上方使用self引用它,则由ARC假定。)

最佳解决方案似乎是更新为latest AFNetworking,{{3}}将操作作为参数传递给块。