ARC,块和保留周期

问题描述:

使用ARC处理目标为4.0和5.0的iOS项目。ARC,块和保留周期

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

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

... do stuff ... 

operation = nil; 
}]; 

在这种情况下,编译器会发出警告,在块是用“操作”将会导致保留周期。在ARC下,__block现在保留该变量。

如果我添加__unsafe_unretained,编译器会立即释放对象,所以很明显,这是行不通的。

我针对4.0,所以我不能使用__weak。

我试图做这样的事情:

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

但同时weakOperation不为零,没有它的属性被填充时,块内。

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

假设进度保证,保留周期可能正是你想要的。你明确地在块的末尾打破了保留周期,所以它不是一个永久的保留周期:当块被调用时,周期被打破。

但是,如果您还有其他操作可以保留操作,则可以将参考存储到__weak__unsafe_unretained变量中,然后使用块中的参考。除非由于某种原因需要在块中更改变量的绑定,否则不需要__block - 对变量进行限定;由于您没有保留周期来破坏,所以您不需要为弱变量分配任何内容。

+1

我已经有了'没有保留周期'的东西,我甚至都没有按照你描述的方式去思考。咄。下一个问题 - 任何方式来沉默编译器警告?它会让我发疯。 – Hunter

+1

请参阅Clang用户手册中的[“通过Pragma控制诊断”](http://clang.llvm.org/docs/UsersManual.html#diagnostics_pragmas)。你只需要弄清楚哪个警告标志要忽略。 –

+4

这是'#pragma clang diagnostic ignored'-Warc-retain-cycles“',由by。 –

这似乎是由康拉德·斯托尔在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 ... 
}]; 

即使你打破参考周期,没有理由阻止保留AFHTTPRequestOperation摆在首位(假设操作会保持自身活着直到t他完成处理程序完成,这并不总是保证但通常如果使用ARC进一步调用堆栈上的self引用由ARC假定和假定。

最好的修复程序似乎是更新到latest AFNetworking,它将操作作为参数传递到块中。

+0

__block不是完全不必要的。默认情况下,所有由块保留的变量都是const内部的,所以你不能改变它们的值。这里__block来拯救。 –