无法理解Objective-C块文档

SCh*_*ang 7 objective-c ios objective-c-blocks

我目前无法理解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);
});
Run Code Online (Sandbox Code Playgroud)
id localVariable = instanceVariable;
dispatch_async(queue, ^{
    /*
      localVariable is used by value, a strong reference is made to localVariable
      (and not to self).
    */
    doSomethingWithObject(localVariable);
});
Run Code Online (Sandbox Code Playgroud)

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

我的问题:

  1. 一个示例究竟是如何"通过引用访问"而另一个示例是通过变量访问的?为什么localVariable"按价值使用?"
  2. 该文件的意思是"强烈参考自我"?它指的是哪个"自我"?
  3. 如果我在第二个例子中将__block存储类型添加到localVariable,我错误地认为该块关闭了变量,所以它将它保留在堆中直到块被释放?还有其他什么事情发生?

谢谢!

ser*_*gio 6

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

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

  1. 当你在方法中定义的块中使用局部变量时,会发生的变化是将变量的内容复制到某个块私有内存中,以便在执行块时(在方法退出后)可用; 在这个意义上,我们可以谈论"按价值"访问(如:复制值); 语法上编译器不知道localVariable引用的内容是什么,所以它的值被视为这样;

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

现在,关于"引用"的使用:在第一种情况下,你得到了对类成员的引用的副本:如果你可以改变它的值(但你不能,因为编译器禁止它),你只是修改一个块私有副本,所以原始对象不受影响.

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

该文件的意思是"强烈参考自我"?它指的是哪个"自我"?

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

如果我在第二个例子中将__block存储类型添加到localVariable,我错误地认为该块关闭了变量,所以它将它保留在堆中直到块被释放?还有其他什么事情发生?

使用__block使变量始终"通过引用"访问,因此您可以修改它们.

这是他们的处理方式:

__block变量存在于变量的词法范围与在变量的词法范围内声明或创建的所有块和块副本之间共享的存储中.因此,如果在帧内声明的块的任何副本存活超出帧的结尾(例如,通过在某处排队以便稍后执行),则存储将在堆栈帧的破坏中存活.给定词法范围中的多个块可以同时使用共享变量.

作为优化,块存储从堆栈开始 - 就像块本身一样.如果使用Block_copy复制块(或者在块发送副本时在Objective-C中复制),则会将变量复制到堆中.因此,__block变量的地址可能会随时间而变化.