我目前无法理解Obj-C块的基本原理和__block存储类型。 来自以下文档:
我正在尝试理解以下段落和示例:
复制块时,会创建对块中使用的对象变量的强引用。如果在方法的实现中使用块:
如果您通过引用访问实例变量,则会对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存储类型修饰符对其进行标记。
我的问题:
谢谢!
答案 0 :(得分:6)
一个例子如何“通过引用访问”,而另一个例子是通过变量访问的?为什么localVariable“按价值使用?”
了解这一点的一种方法如下:
当您在方法中定义的块中使用局部变量时,会发生的变化是将变量的内容复制到某个块专用内存中,以便在执行块时可用(在方法退出);在这个意义上,我们可以谈论“按价值”访问(如:复制值);从语法上讲,编译器不知道localVariable
的内容是指什么,所以它的值被视为这样;
当直接访问类的方法中定义的块中的instanceVariable
时,编译器知道我们正在访问正在执行该方法的同一对象,并且不需要复制任何东西,因为该对象的寿命比找到该块的方法长;但是我们需要确保在执行块时对象仍然存在,所以我们得到了一个强引用。
现在,关于“引用”的使用:在第一种情况下,你得到了对类成员的引用的副本:如果你可以改变它的值(但你不能,因为编译器禁止它),你只是修改一个块私有副本,所以原始对象不受影响。
在第二种情况下,您可以修改instanceVariable
的值(例如:它是nil
并且您分配了一个通过它引用的对象),这将影响执行该方法的对象块已定义。
该文件的意思是“强烈参考自我”?它指的是哪个“自我”?
self
是当前正在执行找到块的方法的对象。强引用只是意味着(在ARC的说法中)对象的保留计数增加(以确保某些其他实体不能通过释放它来解除分配)。
如果我在第二个例子中将__block存储类型添加到localVariable,我错误地假设该块关闭了变量,所以它会在堆中保留它直到块被释放?还有其他什么事情发生?
使用__block
使变量始终“通过引用”访问,因此您可以修改它们。
这是他们的处理方式:
__块变量存在于存储中,该存储在变量的词法范围与在变量的词法范围内声明或创建的所有块和块副本之间共享。因此,如果在帧内声明的块的任何副本存活超出帧的结尾(例如,通过在某处排队以便稍后执行),则存储将在堆栈帧的破坏中存活。给定词法范围内的多个块可以同时使用共享变量。
作为优化,块存储从堆栈开始 - 就像块本身一样。如果使用Block_copy复制块(或者在块发送副本时在Objective-C中复制),则会将变量复制到堆中。因此,__block变量的地址可能会随着时间而变化。