7

我目前无法理解 Obj-C 块和 __block 存储类型的基础知识。从以下文档:

http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW6

我试图理解以下段落和示例:

复制块时,它会创建对块内使用的对象变量的强引用。如果在方法的实现中使用块:

如果通过引用访问实例变量,则会对 self 进行强引用;如果您按值访问实例变量,则会对该变量进行强引用。以下示例说明了两种不同的情况:

dispatch_async(queue, ^{
    // instanceVariable is used by reference, a strong reference is made to self
    doSomethingWithObject(instanceVariable);
});

id localVariable = instanceVariable;
dispatch_async(queue, ^{
    /*
      localVariable is used by value, a strong reference is made to localVariable
      (and not to self).
    */
    doSomethingWithObject(localVariable);
});

要覆盖特定对象变量的此行为,您可以使用 __block 存储类型修饰符对其进行标记。

我的问题:

  1. 一个示例究竟是如何“通过引用访问”而另一个示例是通过变量访问?为什么 localVariable “按值使用”?
  2. 文档中的“强烈引用自我”是什么意思?它指的是哪个“自我”?
  3. 如果我在第二个示例中将 __block 存储类型添加到 localVariable ,我是否错误地假设块关闭了变量,因此它将它保留在堆中直到块被释放?还有哪些事情正在发生?

谢谢!

4

1 回答 1

6

一个示例究竟是如何“通过引用访问”而另一个示例是通过变量访问?为什么 localVariable “按值使用”?

理解这一点的一种方法如下:

  1. 当您在方法中定义的块中使用局部变量时,发生的情况是变量的内容被复制到某个块私有内存中,以便在执行块时(方法退出后)可用;从这个意义上说,我们可以谈论“按值”访问(如:值被复制);从语法上讲,编译器不知道 的内容localVariable指的是什么,因此它的值被视为这样;

  2. 当直接访问instanceVariable在类的方法中定义的块时,编译器知道我们正在访问正在执行该方法的同一对象,并且不需要复制任何内容,因为该对象的生命周期比执行该方法的方法更长。找到块;但是我们需要确保块执行时对象仍然存在,因此我们得到了对它的强引用。

现在,关于“通过引用”的使用:在第一种情况下,您会获得对类成员的引用的副本:如果您可以更改其值(但您不能,因为编译器禁止它),您只是修改了一个块私有副本,所以原始对象不受影响。

在第二种情况下,您可以修改的值instanceVariable(例如:它是nil并且您分配通过它引用的对象),这将影响在定义块时执行该方法的对象。

文档中的“强烈引用自我”是什么意思?它指的是哪个“自我”?

self是当前正在执行找到块的方法的对象。进行强引用仅意味着(在 ARC 用语中)对象的保留计数增加(以确保某些其他实体不能通过释放它来释放它)。

如果我在第二个示例中将 __block 存储类型添加到 localVariable ,我是否错误地假设块关闭了变量,因此它将它保留在堆中直到块被释放?还有哪些事情正在发生?

Using__block使变量始终“通过引用”访问,因此您可以修改它们。

这是它们的处理方式:

__block 变量存在于变量的词法范围和在变量的词法范围内声明或创建的所有块和块副本之间共享的存储中。因此,如果在帧内声明的块的任何副本在帧结束后仍然存在(例如,通过在某处排队以供以后执行),则存储将在堆栈帧的破坏中幸存下来。给定词法范围内的多个块可以同时使用一个共享变量。

作为一种优化,块存储从堆栈开始——就像块本身一样。如果块是使用 Block_copy 复制的(或者在 Objective-C 中,当块被发送一个副本时),变量被复制到堆中。因此,__block 变量的地址会随着时间而改变。

于 2013-01-22T17:25:59.890 回答