【发布时间】:2011-12-21 07:28:24
【问题描述】:
在 Objective-C 中,我知道块被视为对象,所以我想知道是否可以将它们存储在数组中。这就引出了一个问题,块是头等对象还是只是为了在对象之间传递它们而将它们视为对象?如果它们是一流的对象,那么它们不应该存储在数组中吗?
【问题讨论】:
标签: objective-c memory-management objective-c-blocks
在 Objective-C 中,我知道块被视为对象,所以我想知道是否可以将它们存储在数组中。这就引出了一个问题,块是头等对象还是只是为了在对象之间传递它们而将它们视为对象?如果它们是一流的对象,那么它们不应该存储在数组中吗?
【问题讨论】:
标签: objective-c memory-management objective-c-blocks
编辑:无需过多介绍,在 ARC 下,您现在可以像任何其他对象一样将块添加到集合中(参见讨论)。
我在下面保留了原始答案,因为它包含一些有趣的技术细节。
这引出了一个问题,是块头等对象还是它们 只是为了在它们之间传递而将它们视为对象 对象?如果它们是一流的对象,那么它们不应该是 可以存储在数组中吗?
块是 Objective-C 对象,其行为与其他 NSObject 非常相似,但有几个关键区别:
块始终由编译器生成。当执行通过块声明时,它们在运行时有效地“分配/初始化”。
最初在堆栈上创建块。如果 Block 要超过当前范围,则必须使用 Block_copy() 或 copy 方法将 Block 移动到堆中(请参阅下面的 ARC 点)。
除了内存管理之外,块实际上没有可调用的 API。
要将块放入集合中,必须首先复制它。 总是。包括在 ARC 下。 (参见 cmets。) 如果不这样做,则存在分配的堆栈 Block 为 autoreleased 的风险,并且您的应用稍后会崩溃。
复制基于堆栈的块也会复制所有捕获的状态。如果您要制作一个块的多个副本,则先复制一次,然后再复制副本更有效(因为复制副本只会增加保留计数,因为块是不可变的)。
在 ARC 下,从方法或函数返回块“正常工作”;它会被自动复制到堆中,并且返回实际上是一个自动释放的块(编译器可能会在某些情况下优化掉自动释放)。即使使用 ARC,您仍然需要先复制块,然后再将其粘贴到集合中。
我写了几篇博文,都提供了introduction to blocks 和一些tips and tricks。你可能会觉得它们很有趣。
而且,是的,将它们添加到字典中非常有用。我编写了一些代码,将块作为命令处理程序放入字典中,其中键是命令名称。非常方便。
【讨论】:
llvm 版本上测试了 Mecki 所说的内容。该错误不再存在,因此块可以安全地存储在容器中,而无需在 ARC 下显式复制。
addObject:(例如)的块文字被复制。
是的,块确实是对象,你可以把它们放在数组中:
NSMutableArray *arr = [NSMutableArray new];
[arr addObject:^(){NSLog(@"my block");}];
void (^ myblock)() = [arr objectAtIndex:0];
myblock();
这会将“我的块”放在控制台中。
【讨论】:
Block_copy;它甚至可能会破坏编译器优化。