关于objective c:何时在带ARC的对象引用上使用__block关键字

When to use __block keyword on object references with ARC

本问题已经有最佳答案,请猛点这里访问。

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


如果要用块内的代码更改标量变量的值,则需要使用__block。捕获的scalar在块内显示为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-概述/

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


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

__block变量存储在变量的词法范围和变量词法范围内声明或创建的所有块和块副本之间共享的存储器中。因此,如果在帧中声明的块的任何副本在帧结束之后仍然存在(例如,通过在某个地方排队等待稍后执行),则存储将在堆栈帧销毁之后继续存在。因此,当需要修改块中的对象或在销毁堆栈帧后需要对象时,可以使用它们。