当多次执行相同的块时,块中的weakSelf和strongSelf会发生什么?

时间:2014-05-19 17:35:46

标签: objective-c objective-c-blocks

前言

根据Clang docs,“对于__weak对象,当前的指针被保留,然后在当前的完整表达式结束时释放。”对我来说这表明如果我这样做:

__weak typeof(self) weakSelf = self;
[self doSomethingInBackgroundWithBlock:^{
    if (weakSelf) {
        [weakSelf doSomethingInBlock];
    }
}];
 注意

如果你在下面提到@dasblinkenlight的答案,你会注意到weakSelf之前nil可能会变成doSomethingBlock

假设doSomethingInBlock确实以weakSelf存在,其余部分应该没有问题,并且weakSelf在执行完成之前不会有nil成为__weak typeof(self) weakSelf = self; [self doSomethingInBackgroundWithBlock:^{ if (weakSelf) { // Guaranteed to be retained for scope of expression [weakSelf doSomethingInBlock]; // weakSelf could possibly be nil before reaching this point [weakSelf doSomethingElseInBlock]; } }]; 的风险。但是,如果我要这样做:

weakSelf

建议使用__weak typeof(self) weakSelf = self; [self doSomethingInBackgroundWithBlock:^{ __strong typeof(weakSelf) strongSelf = weakSelf; if (strongSelf) { [strongSelf doSomethingInBlock]; [strongSelf doSomethingElseInBlock]; } }]; 并将其转换为块内的强变量,如下所示:

weakSelf

问题

在同一个块的多次迭代中,strongSelfprocessBlock()会发生什么?是否有可能在processBlock(下图)中,某些物体可能存在自我而不存在其他物体?

示例

例如,如果我使用类似的东西在后台处理一个对象数组,那么- (void) processValuesInBackgroundWithArray:(NSArray *)array usingBlock:(void (^)(id))processBlock { for (id ob in array) { // Block is called for each Object // Is there a chance that self will exist for some objects and not for others? processBlock(ob); } } 包含对self的引用:

__weak typeof(self) weakSelf = self;
[self processValuesInBackgroundWithArray:someArray usingBlock:^(id object) {
    __strong typeof(weakSelf) strongSelf = weakSelf;
    if (strongSelf) {
        [self doSomethingWithObject:object];
        [self doSomethingElseWithObject:object];
    }      
}];

这样称呼:

strongSelf

因此该块引用weakSelf中的strongSelf,但该块被多次执行。在数组中的对象迭代之间,nil是否有可能变为{{1}}?

1 个答案:

答案 0 :(得分:3)

我们无法保证在您的第一个示例中weakSelf内的if为非nil,因为该块有两个引用它的完整表达式:

  • if (weakSelf)检查是第一个完整表达式
  • weakSelf调用[weakSelf doSomethingInBlock];是第二个。

因此,即使只有一个strongSelf调用"受保护",也应该应用weakSelf的技巧。通过if声明。

  

是否有可能在processBlock()(下面)中,self可能存在于某些对象而不存在于其他对象中?

由于__strong调用之前的堆栈帧中没有保证processValuesInBackgroundWithArray:引用,self可能会在循环的迭代之间释放,但仅限于调用您的上一个代码段发生在__weak或对包含上一个代码段中方法的对象的未经许可的引用。

我们假设您的最后一个代码段位于一个名为testWeak的方法中,位于名为MyClass的类中:

-(void)testWeak {
    __weak typeof(self) weakSelf = self;
    [self processValuesInBackgroundWithArray:someArray usingBlock:^(id object) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        if (strongSelf) {
            [self doSomethingWithObject:object];
            [self doSomethingElseWithObject:object];
        }      
    }];
}

当这样的呼叫发生时

[myClassObj testWeak];

myClassObj__strongself内的testWeak对象将通过强引用myClassObj保留在调用之外,因此您的代码将会无论有没有strongSelf技巧,都要好。

但是当myClassObj较弱时,最后一个__strong引用会与正在运行的循环同时释放,循环中的某些对象最终会看到nil {{1}在块内。 weakSelf将要做的唯一区别是阻止strongSelfdoSomethingElseWithObject会被调用,而nil将会调用非doSomethingWithObject对象