在下面的示例中,我不明白为什么 localVariable
是通过 doSomethingWithObject
中的值访问的。是什么导致了这种转变?如何区分按值访问变量和按引用访问变量?如果可能,我希望看到更多相关示例。
以下是 Apple 的 Blocks Programming Topics 的摘录并显示实例变量如何保留在 block 中。
If you use a block within the implementation of a method, the rules for memory management of object instance variables are more subtle:
- If you access an instance variable by reference,
self
is retained;- If you access an instance variable by value, the variable is retained.
The following examples illustrate the two different situations:
dispatch_async(queue, ^{ // instanceVariable is used by reference, self is retained doSomethingWithObject(instanceVariable); }); id localVariable = instanceVariable; dispatch_async(queue, ^{ // localVariable is used by value, localVariable is retained (not self) doSomethingWithObject(localVariable); });
最佳答案
这是因为当您直接访问实例变量时,编译器(或多或少)会将其转换为结构成员查找。所以:
[ivar doSomething];
成为
[self->ivar doSomething];
因为需要self
,所以必须保留self
。但是,当您将指针值复制到新变量中时,您知道不再需要 self
结构来知道指针值是什么,因此 self
不需要保留,因为指针值可以从堆栈中复制 const
。实例变量不会发生这种情况(因为在创建 block 和执行 block 之间,ivar 可能会发生变化)。
澄清:
- block 必须保留它在内部引用的所有对象,以确保这些对象在 block 的生命周期内继续存在。
- 当您直接在代码中访问 ivar 时,您实际上只是在查找结构的成员(因为 Objective-C 对象实际上只是结构)
- 查找一个结构的成员意味着你必须拥有该结构
- 因此, block 将保留结构(在本例中为
self
),以便查找始终成功。如果它不这样做,那么self
将来可能会被释放,现在结构查找会导致错误访问(很可能)并且您的应用程序会崩溃。 - 或者,您可以在当前堆栈帧中本地创建一个新的对象指针。这样做的好处是您不再需要保留
self
,因为self
不再参与检索相关对象的地址 - 当然,局部变量引用的对象将被保留,以确保它在 block 的生命周期内存在。
- 在此处使用术语“按值”和“按引用”是完全不正确的。 Objective-C 中的对象总是通过引用传递,因为我们总是传递指针。您不能在 Objective-C 中按值传递对象。 (对此有一些注意事项,但您真的不想去那里)有关按值传递与按引用传递的含义的更多信息,请查看以下问题:What's the difference between passing by reference vs. passing by value?
关于objective-c - 按值或引用访问变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6433348/