如何在没有不必要的保留/释放呼叫的情况下安全地使用ARC和MRC方法?

时间:2017-09-23 01:35:22

标签: objective-c automatic-ref-counting manual-retain-release

我有一个ARC类,其代码如下:

[object doStuffWithObject:otherObject];

object的{​​{1}}方法是使用ARC编译的,就是这样:

-doStuffWithObject:

- (void)doStuffWithObject:(id)otherObject { DoStuffHelper(object, otherObject); } 是一个C函数,使用ARC编译(出于性能原因)。在DoStuffHelper,我是否需要在开始时为DoStuffHelper-retain以及object致电otherObject

4 个答案:

答案 0 :(得分:2)

请参阅高级内存管理:实际内存管理中的Avoid Causing Deallocation of Objects You’re Using,其中指出"收到的对象通常应该在调用方法的整个范围内保持有效&#34 ;,即retainrelease是没有必要的,除了以下警告:

  

此规则偶尔有例外,主要分为两类。

     
      
  1. 从一个基本集合类中删除对象时。

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

    当从其中一个基本集合类中删除对象时,会向其发送release(而不是autorelease)消息。如果集合是已删除对象的唯一所有者,则会立即取消分配已删除的对象(示例中为heisenObject

  2.   
  3. 取消分配“父对象”时。

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

    在某些情况下,您从另一个对象检索对象,然后直接或间接释放父对象。如果释放父节点导致它被释放,并且父节点是子节点的唯一所有者,那么子节点(示例中的heisenObject)将同时被释放(假设它被发送而不是而不是父{q}方法中的autorelease消息。

  4.         

    为防止出现这些情况,您在收到后会保留dealloc,并在完成后将其释放。例如:

    heisenObject
如果您的助手功能属于其中一个类别,我会感到惊讶。如果没有heisenObject = [[array objectAtIndex:n] retain]; [array removeObjectAtIndex:n]; // Use heisenObject... [heisenObject release]; retain,你可能会没事,但我只是为了充分披露而提及它。

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

此外,如果您的效用函数正在创建并返回一个对象,那么这将是另一回事(例如,您通常会返回release个对象。

答案 1 :(得分:1)

在绝大多数情况下,您不会发现ARC比传统的保留/释放慢。您是否使用过仪器来验证问题?

话虽如此,您不需要在DoStuffHelper()中保留/释放对象,因为retainCount在输入时已经是> = 1。如果将对象存储在静态或全局中,则需要保留它们。

答案 2 :(得分:1)

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

答案 3 :(得分:1)

  

DoStuffHelper是一个C函数,不是用ARC编译的(为了提高性能)   原因)。

您是否有任何表现ARC较慢的性能测量结果?

一般情况下,启用优化程序生成的ARC'd可执行文件比禁用ARC(并由编译器优化)的相同代码更快

这是因为编译器(和运行时)可以推断出能够避免调用retainrelease(更糟糕的是,autorelease)的引用。其中所述呼叫在正确的MRR代码中是强制性的。

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

(诚然,这是一个元回答。它质疑是否需要这样的ARC-MRR接口。保持部分ARC和部分MRR的代码库,这种混合物充满了脆弱性。)