ARC支持调度队列吗?

97

我正在阅读苹果关于“调度队列的内存管理”文档:

即使您实现了垃圾回收的应用程序,也必须仍然保留和释放您的调度队列和其他调度对象。 Grand Central Dispatch不支持用于回收内存的垃圾收集模型。

我知道ARC不是垃圾收集器,但我想确定我是否需要dispatch_retain和dispatch_release我的dispatch_queue_t。

Note: - "Grand Central Dispatch"翻译成“中心调度”,即GCD。 - "retain"翻译成“保留”或“增加引用计数”,"release"翻译成“释放”或“减少引用计数”。
2个回答

236

简短回答:是的,ARC会保留和释放调度队列。







长篇回答如下:

如果您的部署目标低于iOS 6.0或Mac OS X 10.8

您需要在队列上使用dispatch_retaindispatch_release,因为ARC不会管理它们。

如果您的部署目标是iOS 6.0或Mac OS X 10.8或更高版本

ARC将为您管理队列。如果启用了ARC,您不需要(也不能)使用dispatch_retaindispatch_release

详细信息

从iOS 6.0 SDK和Mac OS X 10.8 SDK开始,每个调度对象(包括dispatch_queue_t)也是一个Objective-C对象。这在<os/object.h>头文件中有记录:

 * By default, libSystem objects such as GCD and XPC objects are declared as
 * Objective-C types when building with an Objective-C compiler. This allows
 * them to participate in ARC, in RR management by the Blocks runtime and in
 * leaks checking by the static analyzer, and enables them to be added to Cocoa
 * collections.
 *
 * NOTE: this requires explicit cancellation of dispatch sources and xpc
 *       connections whose handler blocks capture the source/connection object,
 *       resp. ensuring that such captures do not form retain cycles (e.g. by
 *       declaring the source as __weak).
 *
 * To opt-out of this default behavior, add -DOS_OBJECT_USE_OBJC=0 to your
 * compiler flags.
 *
 * This mode requires a platform with the modern Objective-C runtime, the
 * Objective-C GC compiler option to be disabled, and at least a Mac OS X 10.8
 * or iOS 6.0 deployment target.
这意味着您可以将队列存储在 NSArrayNSDictionary 中,或者使用带有 strongweakunsafe_unretainedassignretain 属性的属性中。这还意味着,如果您从块中引用队列,该块将自动保留队列。
因此,如果您的部署目标至少为 iOS 6.0 或 Mac OS X 10.8,并且启用了 ARC,则 ARC 将保留和释放您的队列,并且编译器将标记任何尝试使用 dispatch_retaindispatch_release 的操作作为错误。
如果您的部署目标至少为 iOS 6.0 或 Mac OS X 10.8,并且禁用了 ARC,则必须手动保留和释放您的队列,通过调用 dispatch_retaindispatch_release 或给队列发送 retainrelease 消息(例如,[queue retain][queue release])。
为了与旧代码库兼容,您可以通过将 OS_OBJECT_USE_OBJC 定义为 0,防止编译器将您的队列视为 Objective-C 对象。例如,您可以将其放入您的 .pch 文件中(在任何 #import 语句之前)。
#define OS_OBJECT_USE_OBJC 0

或者您可以在构建设置中添加OS_OBJECT_USE_OBJC=0作为预处理器宏。如果将OS_OBJECT_USE_OBJC设置为0,ARC将不会为您保留或释放队列,您需要使用dispatch_retaindispatch_release自行处理。


1
请注意,新的更改将调度对象指定为Objective-C对象。因此,即使禁用ARC,这些对象也会在被块捕获时自动保留 - 就像所有其他Objective-C对象一样。 - Jody Hagins
3
有一个有趣的特殊情况。如果你的库部署在 iOS 5.1 并且你的应用程序部署在 6.0,并且你正在使用 ARC,那么你需要在 5.1 的 dealloc 代码中同时使用 dispatch_releaseNULL 对象。否则,某些东西(编译器生成的代码?运行时本身?)将尝试第二次释放对象。 - Steven Fisher
在使用Mac OS 10.7时,我创建的其他源对象是否需要进行调度? - p0lAris
在 OS X 10.7 下,您必须手动保留/释放所有 GCD 对象。 - rob mayoff

23

在这里进行跟进...如果您的最低部署目标是iOS 6,则ARC现在会管理它们。


这也适用于Mountain Lion。如果您的部署目标是iOS 6或Mountain Lion,则默认情况下不能使用dispatch_release,因为它是一个宏,会向对象发送释放消息,这在ARC下是不允许的。 - Emil Eriksson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接