如何在没有不必要的 retain/release 调用的情况下安全地在 ARC 和 MRC 方法之间切换?

How can I safely go between ARC and MRC methods without unnecessary retain/release calls?

我有一个 ARC class,代码如下:

[object doStuffWithObject:otherObject];

object-doStuffWithObject:方法是用ARC编译的,是这样的:

- (void)doStuffWithObject:(id)otherObject
{
    DoStuffHelper(object, otherObject);
}

DoStuffHelper,一个 C 函数,不是 使用 ARC 编译(出于性能原因)。在 DoStuffHelper 中,我需要在开始时为 object 调用 -retain 并在最后为它们调用 otherObject-release 吗?

在绝大多数情况下,您不会发现 ARC 比传统 retain/release 慢。有没有用Instruments验证问题?

话虽如此,您不需要 retain/release DoStuffHelper() 中的对象,因为 retainCount 在入口时已经 >= 1。如果将对象存储在静态或全局中,那么您将需要保留它们。

没有。 DoStuffHelper 不是声明 objectotherObject 所有权的对象。它只是一个直接对它们进行操作的实用函数。实际上,它是 ARC class 的一部分,它已经在对这些对象执行完整的内存管理。

参见高级内存管理:实用内存管理中的Avoid Causing Deallocation of Objects You’re Using,其中他们指出"received objects should typically remain valid throughout the scope of the calling method",即retainrelease 不是必需的,除非有以下警告:

There are occasional exceptions to this rule, primarily falling into one of two categories.

  1. When an object is removed from one of the fundamental collection classes.

    heisenObject = [array objectAtIndex:n];
    [array removeObjectAtIndex:n];
    // heisenObject could now be invalid.
    

    When an object is removed from one of the fundamental collection classes, it is sent a release (rather than autorelease) message. If the collection was the only owner of the removed object, the removed object (heisenObject in the example) is then immediately deallocated.

  2. When a “parent object” is deallocated.

    id parent = <#create a parent object#>;
     // ...
     heisenObject = [parent child] ;
     [parent release]; // Or, for example: self.parent = nil;
     // heisenObject could now be invalid.
    

    In some situations you retrieve an object from another object, and then directly or indirectly release the parent object. If releasing the parent causes it to be deallocated, and the parent was the only owner of the child, then the child (heisenObject in the example) will be deallocated at the same time (assuming that it is sent a release rather than an autorelease message in the parent’s dealloc method).

To protect against these situations, you retain heisenObject upon receiving it and you release it when you have finished with it. For example:

heisenObject = [[array objectAtIndex:n] retain];
[array removeObjectAtIndex:n];
// Use heisenObject...
[heisenObject release];

如果您的辅助函数属于这些类别之一,我会感到惊讶。如果没有 retainrelease,您可能会没事,但我只是为了全面披露才提到它。

显然,如果您的函数出于其他原因需要它,您可能需要自己的 retainrelease(例如,如果任务是异步的,或者如果您正在做一些不寻常的事情,对象必须长寿调用方法的范围),但我怀疑如果你正在做其中一件事情,你会提到它。

此外,如果您的效用函数正在创建和返回一个对象,那就另当别论了(例如,您通常 autorelease 要返回的对象)。

DoStuffHelper, a C function, is not compiled with ARC (for performance reasons).

您是否有任何性能测量显示 ARC 速度较慢?

一般来说,打开优化器生成的 ARC 可执行文件将比禁用 ARC(并由编译器优化)的相同代码更快

这是因为编译器(和运行时)可以对引用进行推理,从而避免调用 retainrelease(更糟糕的是,autorelease) 其中所述调用在正确的 MRR 代码中是强制性的。

如果您的代码模式不是这种情况,我想捕获所述模式并提交错误。

(不可否认,这是一个元答案。它质疑是否需要这样的 ARC-MRR 接口。维护了部分 ARC 和部分 MRR 的代码库,这种混合充满了脆弱性.)