【问题标题】:Objective-C returning alloc'd memory in a function == bad?Objective-C 在函数中返回分配的内存 == 不好?
【发布时间】:2010-12-13 15:53:43
【问题描述】:

这是在 iPhone 上。

如果我有这样的功能呢

- (SomeObject*)buildObject;

我是否需要传入一个我已经分配到外部的变量

- (void)assignObject(SomeObject** out);

我可以吗

- (SomeObject*)buildObject
{
   return [[[SomeObject alloc] init] autorelease];
}

并像使用它

SomeObject* obj = [[otherObject buildObject] retain];

我想做最后一个,但据我所知,这是未定义的,因为 autorelease 只保证对象直到函数结束?

【问题讨论】:

  • 附注一下,objective-c 命名约定建议您应该将 buildObject 便捷方法命名为“object”,就像 NSArray 具有返回自动释放数组的便捷方法 [NSArray array] 一样。
  • 另外,它应该是类方法 (+) 而不是实例方法 (-),除非出于其他原因。

标签: iphone objective-c memory-management


【解决方案1】:

在 Objective-C 中,内存管理契约如下:调用 alloc 的人负责调用 release。如果构造函数调用 [[[Class alloc] init] release] 则对象被快速创建和销毁。

要解决这个问题,构造函数需要使用 autorelease,如下所示:

return [[[Class alloc] init] autorelease];

这将在当前运行循环结束时注册要释放的对象,除非有东西保留它,例如构造函数的调用者。在您的情况下,第二个示例正是您想要做的。

所以:

- (SomeClass*) buildObject {
   return [[[SomeClass alloc] init] autorelease];
}

- (void) doSomething {
   c = [self buildObject];
   // Call [c retain] if you want c to stay around after the current run
   // loop is finished and clean it up later, e.g. in your delloc method.
}

【讨论】:

  • 所以如果我不想在doSomething之外使用它,我不必立即调用retain?
  • 是的。该对象(如果它是一个自动释放的对象)保证会保留在内存中,直到当前方法结束,但不会更长。它可能寿命更长,但你不能依赖它。
  • (当然,假设您没有自己的自动释放池)
  • 所以你不同意 Bryan SanHolo?如果 doSomething 做了一些冗长的计算,c 不能保证在函数结束时就在那里?
  • 不,Bryan 是正确的,我并不反对他。 ;) c 保证在整个 doSomething 方法中都存在,但是当该方法结束时,池可能会被清理并且 c 消失.如果您从 doSomething 中调用另一个方法,则 c 仍将存在,因为 doSomething 尚未结束。
【解决方案2】:

关于如何在 Cocoa 中执行此操作有一种解决方案;阅读文档了解详情。

基本上,如果您有一个以 initnewcopy 开头的方法,则返回一个保留的对象,并且必须释放它。
如果您提供 方便 方法,则返回一个自动释放的对象。

这意味着:

- (id) initMyObject
{
    self = [super init];
    if (self) {
        // do something
    }
    return self
}

➔你必须释放通过这个方法获得的对象

- (MyObject *) myObject
{
    return [[[MyObject alloc] initMyObject] autorelease];
}

➔ 这是一种方便的方法 - 对象由该方法自动释放,并且您必须保留它如果您想保留它比自动释放池清空(您应该假设发生在当前方法的结尾)。

【讨论】:

  • 此外,关于 Clang 静态分析器的一个巧妙之处在于,如果您在保留或自动释放对象作为返回值时未正确遵循方法的命名约定,它会警告您。这是一个很好的健全性检查。
【解决方案3】:

Autorelease 保证对象直到当前 NSAutoreleasePool 的释放/耗尽。

从方法返回自动释放的对象是完全可以接受的(也是标准做法)。

【讨论】:

    【解决方案4】:

    你可以做你想做的事。在当前自动释放池被释放之前,自动释放不会向对象发出释放消息。发生这种情况要么是因为您明确请求它(通过分配+初始化 NSAutoreleasePool 并稍后将其耗尽),要么是因为系统这样做了。系统自动释放池的创建和排出发生在事件周期的开始和结束;来自内存管理编程指南:

    应用程序工具包自动 在一个开始时创建一个池 事件循环(或事件循环迭代), 例如鼠标按下事件,以及 最后释放它,所以你的代码 平时不用担心 他们。

    实际上,这意味着您想要做的事情是安全的,因为您编写的所有代码都将在一个事件周期内一起执行。

    【讨论】:

    • " 自动释放保证对象在当前自动释放池被释放之前一直存在" 不,它不会。自动释放只不过是一种延迟消息机制。它什么都不能保证。
    • 好点——我说错了。自动释放保持其对对象的引用计数句柄,直到当前自动释放池被释放。
    【解决方案5】:

    使用最后一个是安全的。我在我的每一个应用程序中都使用这种风格,从来没有遇到过问题。自动释放会持续很多很多很多的执行周期,比函数结束的时间要长得多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-15
      • 2017-06-16
      • 2012-06-02
      • 1970-01-01
      • 2012-07-29
      相关资源
      最近更新 更多