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

Log*_*gan 7 objective-c objective-c-blocks

前言

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

__weak typeof(self) weakSelf = self;
[self doSomethingInBackgroundWithBlock:^{
    if (weakSelf) {
        [weakSelf doSomethingInBlock];
    }
}];
Run Code Online (Sandbox Code Playgroud) 注意

如果您在下面引用@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];
    }
}];
Run Code Online (Sandbox Code Playgroud)

建议的解决方法是weakSelf将其转换为块内的强变量,如下所示:

__weak typeof(self) weakSelf = self;
[self doSomethingInBackgroundWithBlock:^{
    __strong typeof(weakSelf) strongSelf = weakSelf;
    if (strongSelf) {
        [strongSelf doSomethingInBlock];
        [strongSelf doSomethingElseInBlock];
    }
}];
Run Code Online (Sandbox Code Playgroud)

发生了什么weakSelf,并strongSelf在同一个块的多次重复?是否有可能在processBlock()(下方),某些物体而不是其他物体存在自我?

例如,如果我在后台使用类似的东西处理对象数组,其中processBlock包含对self的引用:

- (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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这样称呼:

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

所以块参照strongSelfweakSelf,但块被执行多次.是否有strongSelf可能nil在数组中的对象迭代之间出现?

das*_*ght 3

不能保证在您的第一个示例中,weakSelf内部if将是 non- nil,因为该块有两个引用它的完整表达式:

  • 检查if (weakSelf)是第一个完整表达式
  • inweakSelf调用[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];
        }      
    }];
}
Run Code Online (Sandbox Code Playgroud)

当这样调用时

[myClassObj testWeak];
Run Code Online (Sandbox Code Playgroud)

并且myClassObj__strongself内部的对象testWeak将通过对 的强引用保留在调用之外myClassObj,因此无论有或没有这个技巧,您的代码都会很好strongSelf

然而,当myClassObj弱时,并且最后一个__strong引用与运行循环同时释放,循环内的某些对象最终会nil weakSelf在块内看到 a 。唯一的区别strongSelf是防止在非对象doSomethingElseWithObject上调用nil,而在doSomethingWithObject非对象上调用nil