【问题标题】:Objective C release, autorelease, and data typesObjective C 发布、自动发布和数据类型
【发布时间】:2010-11-16 05:10:40
【问题描述】:

我是内存管理代码的新手,但我很清楚这个想法。

在通过 XCode 中的泄漏工具使用我的应用程序时,我注意到我只需要清理我的自定义对象,而不是例如动态创建的数组,因此我认为这些数据类型是自动释放的 - 因为我只需要释放我用作具有(保留)属性的数组。

然后我注意到一些奇怪的事情:我在某个像这样初始化的数组上出现泄漏:

NSMutableArray *removals = [NSMutableArray new];

但不是类似的

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:9];

现在,一个设置为“new”的原因是它可以有 0-99 个项目,而我知道的另一个总是 9。因为两个数组稍后都传递给同一个方法根据用户交互,如果我没有在方法结束时释放,或者如果我释放了,我会得到泄漏!

我把第一个数组改成

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

我没有泄漏,也不必释放任何东西。谁能解释一下?

【问题讨论】:

    标签: iphone objective-c xcode release retain


    【解决方案1】:

    memory management rules 中所述,只要您拥有使用+alloc+new-copy-mutableCopy 创建的对象,您就拥有它并负责在某个时候释放它. (事实上​​,+new 只是[[MyClass alloc] init] 的简写。)正如您所指出的,通过[NSArray new] 创建数组而不释放它是内存泄漏。但是,如果您正确处理此对象,通常可以在某个时候释放它。例如:

    • 如果使用该数组的方法是从创建该数组的方法中调用的,那么您应该能够在使用该数组后释放该数组。如果内部方法需要保持对数组的更永久引用,则该方法负责将-retain 和最终-release 发送到对象。例如:

      - (void)myMethod {
          NSArray *removals = [NSArray new];
          // ...
          [someObject someOtherMethod:removals];
          [removals release];
      }
      
    • 如果您在 -init 方法 中为对象创建了数组,则 -dealloc 方法 可以在对象被销毁时释放它。

    • 如果您需要创建数组然后从方法中返回它,那么您已经发现了自动释放被发明的原因。您的方法的调用者不负责释放该对象,因为它不是+alloc+new-copy-mutableCopy 方法,但您需要确保它最终被释放。在这种情况下,您在返回对象之前手动调用-autorelease。例如:

      - (NSArray *)myMethod {
          NSArray *removals = [NSArray new];
          // ...
          return [removals autorelease];
      }
      

    当您通过+arrayWithCapacity: 创建数组时,您不会调用“特殊”方法之一,因此您不必释放结果。这可能是用-autorelease 实现的,很像上面的最后一个例子,但不一定。 (顺便说一句,您也可以使用[NSMutableArray array] 创建一个空的自动释放的 NSMutableArray;该方法在 NSArray 中找到,因此它不会出现在 NSMutableArray 下的文档中,但它会在发送到 NSMutableArray 类时创建一个可变数组。 ) 如果你打算从你的方法中返回数组,你可以使用它作为[[[NSMutableArray alloc] init] autorelease] 的简写——但这只是一个快捷方式。不过,在很多情况下,您可以使用-init+new 创建一个对象,并在适当的时候手动释放它。

    【讨论】:

      【解决方案2】:

      这就是幕后实现的方式:

      +(NSMutableArray*) new
      {
          return [[NSMutableArray alloc] init];
      }
      

      +(NSMutableArray*) arrayWithCapacity:(NSNumber)capacity
      {
          return [[NSMutableArray alloc] initWithCapacity:capacity] **autorelease**];
      }
      

      在第一种情况下,仅分配数组,您负责取消分配它。相反,arrayWithCapacity 已为您自动释放,即使您忘记释放也不会导致泄漏。

      【讨论】:

        【解决方案3】:

        Cocoa 使用某些命名约定。任何以 alloc、new 或 copy 开头的内容都会返回 retainCount 为 1 的内容,并且您需要释放。函数返回的其他任何东西都有一个平衡的 retainCount(它可能被其他东西持有,或者它可能被保留并被释放)。

        所以:

        NSMutableArray *removals = [NSMutableArray new];
        

        retainCount 为 1,并且:

        NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];
        

        NSMutableArray *removals = [NSMutableArray array];
        

        不要因为方法没有以 alloc、new 或 copy 为前缀。这在内存管理documentation 中有详细说明。特别是:

        如果你拥有一个对象的所有权 使用其名称的方法创建它 以“alloc”或“new”或 包含“copy”(例如,alloc, newObject 或 mutableCopy),或者如果您 向其发送保留消息。你是 负责放弃 您拥有的对象的所有权 释放或自动释放。任何其他时间 你收到一个对象,你不能 释放它。

        【讨论】:

        • 所有这些方法都返回一个保留计数为 1 的对象。不同之处在于,有些人拥有该对象,因此需要释放它,而其他你不拥有该对象并且不需要释放它(但也不能指望它超过当前调用链)。
        • 严格来说,他们没有,它是一个实现细节。在许多情况下,它们返回具有不同保留计数的东西。例如 =[UIImage imageNamed:] 可能会返回具有非常大的 retainCount 的内容,因为它可以重用缓存的图像。
        • 嗯,是的,保留计数本身就是一个实现细节。苹果的文档也说了这么多。在上面列出的所有情况下,在当前版本的 OS X 上,这个实现细节的值是 1。
        • 当然。严格来说,没有人应该真正考虑绝对保留计数,而不是相对保留计数(包括任何未决的自动释放)。在这些术语中,根据隐含所有权,所有内容都返回 +1 或 0。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-25
        • 1970-01-01
        • 2011-04-29
        • 1970-01-01
        • 1970-01-01
        • 2012-04-10
        相关资源
        最近更新 更多