块和self在被调用的方法中的作用

9

好的,我了解如何通过块来避免 self 引用环,那么如果在调用堆栈更深层次的块中从方法发送消息给 self 时该怎么办呢:

- (void)methodA {
    __block MyClass *blockSelf = self;
    [someObject block:^{
        [blockSelf methodB];
    }];
}

- (void)methodB {
    ...
    [self methodC];
    ...
}

- (void)methodC {
}

在这种情况下,[blockSelf methodB] 是可以的,但是从 methodB 中发送 [self methodC] 是否会导致循环引用呢?无法在任何地方找到答案...
1个回答

8

这里没有保留环。当一个块字面量在方法内部定义时,块可以捕获的上下文被限制为仅限于该方法内部可见的内容。在你的例子中:

- (void)methodA {
    __block MyClass *blockSelf = self;
    [someObject block:^{
        [blockSelf methodB];
    }];
}

块文字,即:
^{
    [blockSelf methodB];
}

能够看到以下内容:
  1. self_cmd,它们是每个Objective-C方法中可用的隐藏参数。如果-methodA有形式参数,则Block字面量也能够看到它们;
  2. 函数/方法块内的任何块作用域变量,即方法内部可见且在Block字面量定义点可见的每个局部变量。在示例中,-methodA内唯一的局部变量是blockSelf,因为它是__block限定的,所以不会被保留;
  3. 任何文件作用域变量(也称为全局变量)。
块字面量不知道(并且在一般情况下不能知道)其他函数/方法中发生的事情,因此调用的函数/方法内可用的任何上下文都不会被块字面量捕获。您只需要关注定义块字面量的方法。 我使用苹果公司的约定,在引用闭包/lambda时将Block大写(即^{}),在引用C blocks时将block小写(即{})。

太棒了,谢谢!这将从我的辅助方法中删除一堆丑陋的“参数黑科技”... - Tom
那里没有保留环。这取决于 someObject 是什么以及它是否保留了传递给它的块。如果 self 保留了 someObject(比如它是实例变量),并且如果 someObject 存储并保留传递给 block: 的块,那么就会有一个保留环。 - newacct

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接