请参阅Assign a variable inside a Block to a variable outside a Block
它说它应该为变量添加__block
,但是我在这里看到objc的Google Youtube示例代码中的一些代码https://code.google.com/p/google-api-objectivec-client/source/browse/trunk/Examples/YouTubeSample/YouTubeSampleWindowController.m
从第279行到第290行:
_channelListTicket = [service executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
GTLYouTubeChannelListResponse *channelList,
NSError *error) {
// Callback
// The contentDetails of the response has the playlists available for
// "my channel".
if ([[channelList items] count] > 0) {
GTLYouTubeChannel *channel = channelList[0];
_myPlaylists = channel.contentDetails.relatedPlaylists;
}
为什么可以在不首先添加_myPlaylists
的情况下分配变量__blocks
?
答案 0 :(得分:6)
为什么可以在不首先添加
_myPlaylists
的情况下分配变量__block
?
因为它不是函数中的局部变量。只有您计划分配的本地人才需要__block
指定。实例变量 * 通过self
引用;他们永远不需要标记为__block
。
* 在示例代码中,您链接_myPlaylists
是在第49行的实现块中声明的实例变量。
答案 1 :(得分:2)
扩展dasblinkenlight的答案:这一切都归结为堆与堆栈。
说不清楚:
堆是发生动态分配的内存区域。每次通过alloc
或类似方法创建新对象时,对malloc
或其中一个亲属进行C调用,或者使用Core Foundation或其他地方的类似方法,存储都会存在于堆上。直到有人归还它为止。仅仅程序流程不会影响堆上的项目。
堆栈是用于管理程序流的内存区域。所以它是局部变量的所在。它实际上还包含所有调用的记录,这些调用下降到程序现在的任何位置 - 每个方法或函数调用都会导致为该调用留出一小部分堆栈。它是一个堆栈,所以它只在一个方向上增长。当方法返回其堆栈的一部分时,将隐式返回给系统以供重用。如果您的程序崩溃,那么谁调用谁是堆栈跟踪的列表,显示堆栈的当前状态。
阻止捕获状态。 State包含堆栈和堆上的内容。在返回堆栈的一部分之后很久就可能存在块。因此,如果您希望堆栈中的变量可以修改,它们必须工作 - 具体来说,它实际上不能存在于堆栈中。 __block
实现了这一目标。默认情况下,项目没有标记,因为它的速度较慢。
所以最后得到你的实际问题:self
已经在堆上分配了。因此,它的生命周期与程序流程没有直接关系。因此,块可以通过引用捕获它并稍后修改其状态。没问题。 _myPlaylists
只是self
的实例变量。
对于堆上的变量(例如局部变量),情况并非如此。该块无法确定其存储在以后访问时仍然合法。到那时,其他人可能正在使用存储器。捕获当前值没有问题,因为在创建块时存储仍然可以安全访问但是您必须使用__block
来标记该变量以在堆上使用存储而不是堆栈我希望以后可以安全地为它写一个新值。