在Objective-C(从Xcode 7开始)中,用于基元的__block
修饰符在Stack Overflow中清楚地解释,例如here和Apple here in the Blocks Programming Guide。如果没有标签,则会捕获基元的副本,并且无法在块内修改原始文本。使用标签,无需复制,并且可以在块中修改原始 。
但是对于指向对象的指针,情况并没有得到很好的解释。 Here Apple说“强烈引用自我”或“强烈引用变量”。但是在页面的最后,Apple说:
要覆盖特定对象变量的此行为,可以使用__block存储类型修饰符对其进行标记。
“覆盖此行为”是什么意思?
更复杂的是,Stack Overflow上的一些帖子谈到在块内调用对象时做出弱引用。
我不试图建立一个对象。我只想从块中修改现有对象的状态。我相信在同一个线程中同步调用该块。
想象:
Clicker* myClicker = [[Clicker alloc] init] ;
…
// Declare a block.
void (^myBlock)( );
// Populate the block.
myBlock = ^ void ( ) {
[myClicker click] ; // Updating some state in that object, such as incrementing a counter number or adding an element to a collection.
};
// Call `myBlock` synchronously (same thread) from some other code.
… // … invokes `myBlock` repeatedly …
我的问题:
如何使用__block
修饰符修改代码?
如何使用弱引用修改代码?
对于从块内修改的对象状态还有哪些其他问题?
答案 0 :(得分:2)
你引用了有点过时的Blocks Programming Topics,其中说:
要覆盖特定对象变量的此行为,可以使用
__block
存储类型修饰符对其进行标记。
该文件可以追溯到人工引用计数的日子,在ARC之前。在手动引用计数代码中,您可以使用__block
来避免在块内引用的对象建立strong reference。
但是,如Transitioning to ARC Release Notes所述,ARC的这种行为已经发生了变化。我们现在在我们不希望建立对块中引用的对象的强引用的情况下使用weak
。 (在特殊情况下,您可以使用unsafe_unretained
,您知道所产生的悬空指针不是问题。)
因此,在处理要在块内变异的基本类型时,请继续使用__block
。但是当处理ARC下的块中的对象时,__block
限定符通常不会进入讨论。问题只是你想要一个强引用还是一个弱引用(或一个不安全的,未保留的引用)。这很大程度上取决于你的应用的object graph,即(a)你是否需要弱/无法参考以防止强引用周期;或者(b)您不希望某些异步执行块不必要地延长块中引用的某些对象的生命周期。这些情况似乎都不是这样的。
答案 1 :(得分:1)
首先,__block
的基本点对于所有类型的变量(原始变量,对象指针变量和所有其他变量)都是相同的 - __block
使变量在外部作用域和捕获它的块的作用域,以便在所有其他作用域中看到对一个作用域中的变量的赋值(=
)。
因此,如果不使用__block
,如果在创建块后分配给对象指针变量以指向块外的另一个对象,则块将不会看到对变量的赋值,并且仍然会看到它指向创建块时它指向的对象。相反,在块内部,您将无法分配给变量。如果您使用__block
,那么指定变量以指向另一个对象(在块内部或外部)将反映在其他范围内。
请注意,对象状态的变化与赋值变量无关。通过在指向对象的指针上调用mutating方法来改变对象的状态,或者可以使用->
语法使用指向对象的指针直接更改字段。这些都不涉及分配给持有指向对象的指针的变量。另一方面,分配给持有指向对象的指针的变量只使指针指向另一个对象;它不会改变任何对象。
您正在阅读的有关强引用和“覆盖此行为”的部分与仅在MRC下的块的内存管理行为的单独问题有关。在MRC下,ARC中没有变量__strong
或__weak
的概念。当MRC中的块捕获对象指针类型的变量时,它默认被捕获为强引用(块保留它,并在块被释放时释放它),因为这是大多数所需的行为。时间。如果您希望块不保留捕获的变量,那么唯一的方法就是使它__block
,这不仅使变量在两个范围之间共享,而且使块不保留变量。所以这两个概念在MRC中混为一谈。
在ARC中,块是强还是弱捕获变量取决于捕获的变量__strong
或__weak
(或__unsafe_unretained
),并且与变量是否完全正交是__block
还是不。你可以拥有__block
而不被弱捕获的对象指针变量,或者在没有__block
的情况下被弱捕获,或者如果你想要的话,都被弱捕获和__block
。