繁体   English   中英

将Objective-C块定义为属性 - 最佳实践

[英]Defining Objective-C blocks as properties - best practice

我最近遇到了一个Apple文档 ,它显示了一个块的以下属性声明:

@interface XYZObject : NSObject
@property (copy) void (^blockProperty)(void);
@end

此外,本文还指出:

注意:您应该将copy指定为属性属性,因为需要复制块以跟踪其在原始范围之外的捕获状态。 在使用自动引用计数时,您不必担心这一点,因为它会自动发生,但属性属性的最佳做法是显示结果行为。 有关更多信息,请参阅块编程主题。

我还阅读了建议的块编程主题,但没有找到任何相关的东西。

我仍然很好奇为什么将块属性定义为“复制”是最佳实践。 如果您有一个好的答案,请尝试区分ARC和MRC差异(如果有的话)。

谢谢

默认情况下,会在堆栈上创建块。 这意味着它们只存在于已创建的范围内。

如果您想稍后访问它们,则必须通过向块对象发送copy消息将它们复制到堆中。 一旦检测到需要在其创建的作用域之外访问块,ARC将立即为您执行此操作。作为最佳实践,您将任何块属性声明为副本,因为这是它在自动内存管理下的应用方式。

有关堆栈与堆的更多信息,请阅读Mike Ash 在Objective-C中读取堆栈和堆对象

默认情况下,块在堆栈上分配。 这是一种优化,因为堆栈分配比堆分配便宜得多。 堆栈分配意味着,默认情况下,当声明的范围退出时,块将不再存在。 因此,具有retain语义的块属性将导致指向不再存在的块的悬空指针。

要将块从堆栈移动到堆(从而为其提供正常的Objective-C内存管理语义和延长的生命周期),必须通过[theBlock copy]Block_copy(theBlock)等复制块。一旦在堆上,块的生命周期可以根据需要通过保留/释放来管理。 (是的,这也适用于ARC,你只需要自己调用-retain / -release 。)

因此,您希望使用copy语义声明块属性,以便在设置属性时复制块,从而避免指向基于堆栈的块的悬空指针。

你所指的“最佳实践”只是简单地说:“无论你在这里写什么,看到ARC都会神奇地复制你的块,你最好明确地写'复制',以免混淆看你代码的后代。”

说明如下:

通常,您不需要复制(或保留)块。 当您希望在销毁声明范围之后使用该块时,您只需要制作一个副本。 复制将块移动到堆。
-Blocks编程主题:使用块,复制块

显然,将一个块分配给一个属性意味着它可以在声明它的范围被破坏后使用。 因此,根据Blocks Programming Topics ,块应该用Block_copy复制到堆中。

但ARC会为您解决这个问题:

在ARC模式下向块传递块时块“正常工作”,例如在返回中。 您不必再调用Block Copy。
- 过渡到ARC

请注意,这与块的retain语义无关 块的上下文根本没有办法存在而不会从(即将被弹出的)堆栈移到堆上。 因此,无论您使用@property限定哪些属性,ARC仍然会复制该块。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM