2013-05-08 77 views
3

我已经写了下面的类别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:(从NSOperationQueue)不显示警告:

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

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

+0

比较:http://stackoverflow.com/a/15536​​473/1187415:'塞玛:: checkRetainCycles()'中,如果方法名称以 “set” 或 “添加” 启动静态分析警告,但*不是*用于“addAsynchronousOperationWithBlock”。 – 2013-05-09 02:25:35

+0

...更正:如果方法名称以“set”或“add”开头,则静态分析器将发出警告,但对于“addOperationWithBlock”,则会发出* not *警告。 – 2013-05-09 08:05:45

+0

我认为你的意思是“addOperationWithBlock”,而不是“addAsynchronousOperationWithBlock”在最后的代码示例? – 2013-05-09 08:20:18

回答

4

提炼别人怎么在这里写:

  1. 无论是代码示例创建了一个持久的保留周期,这种保留周期将会串联存储器。
  2. Xcode抱怨你的addAsynchronousOperationWithBlock方法,因为它有一个可疑的名字。它不会抱怨addOperationWithBlock,因为它具有关于addOperationWithBlock的特殊知识,可以覆盖其怀疑。
  3. 要摆脱警告,请使用__weak(请参阅jszumski和matt的答案)或将addAsynchronousOperationWithBlock重命名为不以“add”或“set”开头。

为了详细说明这些位:

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

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

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

+0

感谢您的好解释。现在,我很清楚。 – Luka 2013-05-14 09:53:41

9

当您在一个块中使用self时,它会被该块捕获,并且可能导致保留周期。当self(或者它有很强的参考意义)对周期发生时有很强的参考。为了避免潜在的周期,宣告一个弱指针和使用,在该块来代替:

YourClassName * __weak weakSelf = self; 

[_queue addAsynchronousOperationWithBlock:^(block signal) { 
    [weakSelf foo:nil]; 
}]; 
+2

具体而言,如果块由自有,即使是间接的。否则就很好。 – 2013-05-08 21:54:28

+0

优秀的一点,我更新了答案,以便更明确。 – jszumski 2013-05-08 22:01:34

+0

好吧,但为什么我不与addOperationWithBlock有同样的问题?这里强烈的参考块在哪里? – Luka 2013-05-08 22:17:47

4

从jszumski答案本质上是正确的,但要获得“弱自我”舞正确的形式是非常重要的。形式(建筑在他的代码)是:

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

+2

我也总是使用这种模式,但实际上该对象可以*不*被释放,如果你只是用'[weakSelf富:无]',比较http://stackoverflow.com/a/15267291/1187415:访问'块中的weakSelf'通过'objc_loadWeak()'完成,它保留并自动释放对象。 – 2013-05-09 02:47:31

+0

感谢您的答案,也为链接。我正在学习很多内容。我仍然对我的问题有些怀疑,我编辑了问题以表达他们 – Luka 2013-05-09 13:28:25

相关问题