何时在ARC对象引用上使用__block关键字

时间:2013-07-24 00:17:48

标签: objective-c automatic-ref-counting objective-c-blocks

我知道块的标量变量需要__block存储类型才能看到它们的更新,但是何时需要对象?我相信在捕获要在块中使用的自引用时应该使用__weak,但我不知道何时需要为普通对象实际使用__block存储类型。

2 个答案:

答案 0 :(得分:15)

如果要使用块内的代码更改其值,则标量变量需要

__block。捕获的标量在块内显示为const,因此无法更改。如果你有一个指向对象的指针,则适用相同的区别 - 捕获的指针本身将是const指针,因此无法修改,但指向的对象可以通过块内的代码进行修改。如果要更改指向的对象,则指针本身必须更改,因此必须使用__block类型声明指针。永远不需要将对象本身声明为__block,而只需要指向对象的指针,并且只有在必须更改指针时才会。

如果你有正确的心理模型,那么阻止就不那么容易了。重要的是要知道块最初是在堆栈上分配的,因此在弹出堆栈帧时销毁词法范围时会消失。如果您希望块在创建块的词法范围的生命周期之后挂起,请使用Block_copy()将其移动到堆中,或者发送-copy消息。将块复制到堆时,所有捕获的const变量都会继续运行,并保留这些const个变量所指向的任何对象。从堆中删除块时,const变量指向的所有对象都将被释放。

__block变量“引擎盖下”有一个额外的间接层,编译器使用(并且你看不到)块,所以当块被复制到堆时,捕获__block个变量,并调整不可见指针以指向这些__block变量的新堆位置。这意味着__block变量的地址可能会发生变化,因此在使用该地址时请务必小心。您还可以看到__block变量在某种意义上存在于块外部,因此可以从块外部的代码读取和修改这些变量。

我一直很简短,但你可以在这里找到更好的解释,列出越来越复杂:

http://ios-blog.co.uk/tutorials/programming-with-blocks-an-overview/

http://www.cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html

http://www.mikeash.com/pyblog/friday-qa-2011-06-03-objective-c-blocks-vs-c0x-lambdas-fight.html

答案 1 :(得分:0)

它们用于功能级变量。这些在块(以及封闭范围)内是可变的,并且如果将任何引用块复制到堆中,则会保留它们。使用__block存储修饰符声明的封闭词法范围的局部变量由引用提供,因此是可变的。任何更改都会反映在封闭的词法范围中,包括在相同的词法范围内定义的任何其他块。

__block变量存在于变量的词法范围与在变量的词法范围内声明或创建的所有块和块副本之间共享的存储中。因此,如果在帧内声明的块的任何副本存活超出帧的结尾(例如,通过在某处排队以便稍后执行),则存储将在堆栈帧的破坏中存活。因此,当您需要修改块中的对象时,或者在销毁堆栈帧后需要对象时,请使用它们。