我为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 :(得分:9)
在块中使用self
时,块会捕获它,而可能会导致保留周期。当self
(或其具有强引用的内容)具有对块的强引用时发生循环。要避免潜在的循环,请声明一个弱指针并在块中使用它:
YourClassName * __weak weakSelf = self;
[_queue addAsynchronousOperationWithBlock:^(block signal) {
[weakSelf foo:nil];
}];
答案 1 :(得分: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 :(得分:4)
提炼其他人写的内容:
addAsynchronousOperationWithBlock
方法,因为它有可疑名称。它不会抱怨addOperationWithBlock
,因为它有addOperationWithBlock
的特殊知识可以覆盖其怀疑。__weak
(请参阅jszumski和matt的答案)或将addAsynchronousOperationWithBlock
重命名为“add”或“set”。详细说明:
如果self
拥有_queue
,您将有一个短暂的保留周期。 self
将拥有_queue
,这将拥有块,而调用[self foo:]
的块将拥有self
。但是一旦块完成运行,_queue
将释放它们,并且周期将被打破。
静态分析器已编程为怀疑以“set”和“add”开头的方法名称。这些名称表明该方法可以永久保留传递的块,可能创建永久保留周期。因此关于你的方法的警告。它并没有抱怨-[NSOperationQueue addOperationWithBlock:]
,因为有人知道NSOperationQueue
在运行它们后会释放阻塞,所以不会抱怨它。
如果您使用__weak
,分析师不会抱怨,因为不会有保留周期的可能性。如果您重命名您的方法,分析仪将不会抱怨,因为它没有任何理由怀疑您的方法永久保留传递给它的块。