Iphone 弧、块和保持循环

Iphone 弧、块和保持循环,iphone,ios,ios5,automatic-ref-counting,afnetworking,Iphone,Ios,Ios5,Automatic Ref Counting,Afnetworking,使用ARC处理针对4.0和5.0的iOS项目 遇到与块、圆弧和从块外部引用对象相关的问题。下面是一些代码: __block AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; [operation setCompletionBlock:^ { if ([operation isCancelled]) { return;

使用ARC处理针对4.0和5.0的iOS项目

遇到与块、圆弧和从块外部引用对象相关的问题。下面是一些代码:

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

... do stuff ...

operation = nil;
}];
在这种情况下,编译器会发出警告,在块中使用“operation”将导致一个retain循环。在ARC下,_块现在保留变量

如果我添加了uu unsafe u unrepaired,编译器会立即释放该对象,显然这是行不通的

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

我试过这样做:

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

[operation setCompletionBlock:^ {
  if ([unretainedOperation isCancelled]) {
    return;
  }
  ... do stuff ...
}];
但是,虽然weakOperation不是nil,但在块内部时,不会填充它的任何属性


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

假设有进度保证,保留周期可能正是您想要的。在块的末尾显式中断保留循环,因此它不是一个永久的保留循环:调用块时,该循环被中断


但是,如果您有其他方法来保持操作,您可以将引用存储到
\uuuu弱
\uuuu不安全\uu未恢复的
变量中,然后从块中使用该变量。无需
\uu block
-限定变量,除非您出于某种原因需要在块期间更改变量的绑定;由于您不再需要中断retain循环,因此不需要为弱变量分配任何内容。

这似乎是康拉德·斯托尔(Conrad Stoll)在中描述的问题,但他的写作遗漏了几个要点:

  • \uu block
    看起来像是苹果推荐的避免在MRC模式下强引用捕获变量的方法,但在ARC模式下完全没有必要。在这种情况下,在ARC模式下完全没有必要;在MRC模式下也不需要这样做,尽管较轻的解决方法更为详细:
    void*unretainedOperation=operation^{AFHTTPRequestOperation*op=unretainedOperation;}
  • 在ARC模式下,您需要一个强引用(以便可以将其添加到队列中)和一个弱/不安全的未恢复引用
最简单的解决方案如下所示:

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

[operation setCompletionBlock:^ {
  if ([unretainedOperation isCancelled]) {
    return;
  }
  ... do stuff ...
}];
即使打破了引用循环,块也没有理由首先保留
AFHTTPRequestOperation
(假设操作在完成处理程序完成之前一直保持活动状态,这并不总是可以保证的,但如果使用调用堆栈上的
self
,则通常是正确的,并由ARC假设)


最好的修复方法是更新到,它将操作作为参数传递到块中。

我已经记住了“无保留周期”的事情,我甚至没有按照您描述的方式来考虑它。Duh.下一个问题-有没有办法让编译器警告静音?这会让我发疯的。请参阅用户手册中的所有。你只需要找出要忽略的警告标志。顺便说一句,这是
#pragma clang diagnostic ignored”-Warc retain cycles“
。对不起,我知道我来晚了,但密切关注@JeremyW.Sherman的开场白(“假设进度保证”)很重要,尤其是在AFNetworking中,因为情况并非如此。在您的示例中,如果操作被取消,则在将操作设置为nil之前返回,在AFHTTPRequestOperation中也是如此。m:setCompletionBlockWithSuccess:…如果操作被取消,则不会调用完成块或错误块,从而保留操作。即使假设有进度保证,引用周期通常也不是“您想要的”,尽管它可能是可以接受的。_块并不是完全不必要的。默认情况下,块保留的所有变量都将是其中的常量,因此您不能更改它们的值。这里_块起到了解救作用。