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:与(from )相同的代码NSOperationQueue不显示警告:

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

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

4

3 回答 3

9

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

YourClassName * __weak weakSelf = self;

[_queue addAsynchronousOperationWithBlock:^(block signal) {
    [weakSelf foo:nil];
}];
于 2013-05-08T21:43:02.227 回答
4

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

YourClassName * __weak weakSelf = self;

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

因此,我们weakSelf通过强引用捕获。如果您不这样做,weakSelf则在您使用它的过程中可能会不复存在(因为您对它的引用很弱)。

有关舞蹈的内容,请参阅我的书,以及您可以对由块引起的潜在保留周期做的其他事情:

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

于 2013-05-09T02:19:44.143 回答
4

提炼其他人在这里写的内容:

  1. 这两个代码示例都没有创建一个持久的保留循环,这种循环会导致内存搁浅。
  2. Xcode 抱怨您的addAsynchronousOperationWithBlock方法,因为它有一个可疑的名称。它不会抱怨,addOperationWithBlock因为它对此有特殊的了解addOperationWithBlock,超过了它的怀疑。
  3. 要消除警告,请使用__weak(参见 jszumski 和 matt 的答案)或重命名addAsynchronousOperationWithBlock为不以“add”或“set”开头。

详细说明这些:

  1. 如果self拥有_queue,您将有一个短暂的保留周期。selfwill own _queue,它将拥有块,调用的块[self foo:]将拥有self。但是一旦块运行完毕,_queue就会释放它们,循环就会被打破。

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

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

于 2013-05-13T14:13:32.307 回答