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

Ios 块很可能导致一个保留周期,ios,objective-c,objective-c-blocks,nsoperationqueue,Ios,Objective C,Objective C Blocks,Nsoperationqueue,我为NSOperationBlock @implementation NSOperationQueue (Extensions) -(void)addAsynchronousOperationWithBlock:(void (^)(block))operationBlock { dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); block signal = ^ { dispatch_s

我为
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
它似乎工作正常,但当我调用它时(如以下代码段所示),我得到一个警告:

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

foo
是使用此类别的类的方法

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

[_queue addOperationWithBlock:^ {
        [self foo:nil];
}];
我真的不明白。 特别是我不明白的是:
我应该在这两种情况下都使用弱指针吗?在我不使用弱指针的情况下,这两个代码段是否会进入一个保留周期

在块内使用
self
时,它会被块捕获,并可能导致保留周期。当
self
(或其具有强引用的对象)具有对块的强引用时,发生循环。为避免潜在循环,请声明弱指针并在块中使用该指针:

YourClassName * __weak weakSelf = self;

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

jszumski的回答本质上是正确的,但重要的是要让“弱自我”舞蹈的形式正确。表格(基于他的代码)为:

因此,我们通过一个强引用来捕获
weakSelf
。如果你不这样做,<代码>弱自我>代码>当你在使用它的时候,它就会消失(因为你对它的引用很弱)。 请参阅我的《舞蹈》一书,以及您可以对由块引起的潜在保留周期所做的其他事情:


要提取其他人在此处所写的内容:

  • 这两个代码示例都不会创建这种类型的持久保留周期 那会使记忆变得模糊
  • Xcode抱怨您的
    addAsynchronousOperationWithBlock
    方法有可疑名称。它不会抱怨
    addOperationWithBlock
    ,因为它对
    addOperationWithBlock
    有专门的了解,可以消除它的怀疑
  • 要消除该警告,请使用
    \uu-weak
    (请参阅jszumski和matt的答案)或重命名
    addAsynchronousOperationWithBlock
    以不以“add”或“set”开头
  • 要详细说明这些问题:

  • 如果
    self
    拥有
    \u队列
    ,您将有一个短暂的保留周期
    self
    将拥有
    \u queue
    ,它将拥有块,而调用
    [self foo:
    的块将拥有
    self
    。但一旦这些块完成运行,
    \u queue
    将释放它们,循环将被打破

  • 静态分析器已被编程为怀疑以“set”和“add”开头的方法名。这些名称表明,该方法可能永久保留传递的块,可能会创建一个永久保留循环。因此,有关您的方法的警告。它不会抱怨
    -[NSOperationQueue addOperationWithBlock:
    ,因为知道
    NSOperationQueue
    在运行块后释放块的人告诉它不要这样做

  • 如果您使用
    \uuuu-weak
    分析仪不会抱怨,因为不可能出现保留周期。如果重命名方法,分析器不会抱怨,因为它没有任何理由怀疑您的方法永久保留传递给它的块


  • 具体来说,如果区块为self所有,甚至是间接拥有。否则就可以了。很好,我更新了答案,使之更明确。好吧,但是为什么我对addOperationWithBlock没有同样的问题呢?这里是块的强引用在哪里?但是代码片段都捕获了自身。分析器在一种情况下抱怨,而在另一种情况下却没有抱怨,原因是一些方法名称硬编码到分析器中,请参阅我对上述问题的评论。还要注意,捕获self通常并不坏-它可以用来保持对象的活动状态,直到调用块为止,compare.compare:
    Sema::checkRetainCycles()
    在静态分析器中,如果方法名称以“set”或“add”开头,而不是“addAsynchronousOperationWithBlock”开头,则会发出警告。。。。更正:如果方法名称以“set”或“add”开头,静态分析器会发出警告,但不是针对“addOperationWithBlock”。我假设您在上一个代码示例中指的是“addOperationWithBlock”而不是“addAsynchronousOperationWithBlock”?我更改了问题以使其更清楚\u queue==self,因此self保留block,block reserves self==\u queue ERGO a cycleI也将始终使用此模式,但实际上,如果仅使用
    [weakSelf foo:nil],则无法释放对象,比较:通过
    objc_loadWeak()
    访问块中的
    weakSelf
    ,它会保留并自动删除对象。谢谢您的回答,也谢谢您的链接。我在读它的时候学到了很多。我仍然对我的问题有一些疑问,我编辑了这些问题来表达我的谢意。现在我明白了。
    YourClassName * __weak weakSelf = self;
    
    [_queue addAsynchronousOperationWithBlock:^(block signal) {
        [weakSelf foo:nil];
    }];
    
    YourClassName * __weak weakSelf = self;
    
    [_queue addAsynchronousOperationWithBlock:^(block signal) {
        YourClassName * strongSelf = weakSelf;
        if (strongSelf)
             [weakSelf foo:nil];
    }];