块很可能会导致一个保留周期

我为NSOperationBlock写了以下类别

 @implementation NSOperationQueue (Extensions) -(void)addAsynchronousOperationWithBlock:(void (^)(block))operationBlock { dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); block signal = ^ { dispatch_semaphore_signal(semaphore); }; [self addOperationWithBlock:^{ operationBlock(signal); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_release(semaphore); }]; } @end 

它似乎工作正常,但当我打电话(如下面的代码片段所示),我得到一个警告:

区块很可能会导致保留周期

 [_queue addAsynchronousOperationWithBlock:^(block signal) { [self foo:nil]; signal(); }]; 

foo是使用这个类的类的一个方法。

addOperationWithBlock:相同的代码addOperationWithBlock:来自NSOperationQueue )不显示警告:

 [_queue addOperationWithBlock:^ { [self foo:nil]; }]; 

我真的不明白这一点。 特别是我不明白的是,在两种情况下,我应该使用弱指针吗? 实际上这两个片段会带来保留周期,以防我不使用弱指针?

提炼其他人在这里写的:

  1. 这两个代码示例都不会创build一个持久的保留循环,这将会导致内存溢出。
  2. Xcode抱怨你的addAsynchronousOperationWithBlock方法,因为它有一个可疑的名字。 它不会抱怨addOperationWithBlock因为它有关于addOperationWithBlock特殊知识来覆盖它的怀疑。
  3. 要摆脱警告,请使用__weak (请参阅jszumski和matt的答案),或者将addAsynchronousOperationWithBlock重命名为不以“add”或“set”开头。

为了详细阐述一下这些:

  1. 如果self拥有_queue ,那么将会有一个短暂的保留周期。 self会拥有自己的_queue ,它将拥有这些块,而调用[self foo:]的块将拥有self 。 但一旦块完成运行, _queue将释放它们,循环将被打破。

  2. 静态分析器已被编程为怀疑以“set”和“add”开头的方法名称。 这些名称表明,该方法可能会永久保留传递的块,可能会创build一个永久的保留周期。 因此警告你的方法。 它不会抱怨-[NSOperationQueue addOperationWithBlock:]因为知道NSOperationQueue在运行后会释放阻塞的人不会被告知。

  3. 如果使用__weak则分析仪不会抱怨,因为不会有保留周期的可能性。 如果你重命名你的方法,分析器不会抱怨,因为它没有任何理由怀疑你的方法永久保留块传递给它。

当你在一个块中使用self ,它被块捕获,并可能导致一个保留周期。 当self (或者有很强的参考意义)对这个块有很强的参考时,就会发生循环。 为了避免潜在的循环,请声明一个弱指针,然后在块中使用它:

 YourClassName * __weak weakSelf = self; [_queue addAsynchronousOperationWithBlock:^(block signal) { [weakSelf foo:nil]; }]; 

jszumski的答案在本质上是正确的,但重要的是让“弱自我”舞蹈的forms正确。 forms(build立在他的代码上)是:

 YourClassName * __weak weakSelf = self; [_queue addAsynchronousOperationWithBlock:^(block signal) { YourClassName * strongSelf = weakSelf; if (strongSelf) [weakSelf foo:nil]; }]; 

因此,我们通过一个强有力的参考来捕捉weakSelf 。 如果你不这样做, weakSelf可以在你使用它的过程中不存在(因为你对它的引用很弱)。

看看我的书跳舞,还有其他的事情,你可以做的潜在的保留周期造成块:

http://www.apeth.com/iOSBook/ch12.html#_unusual_memory_management_situations