【问题标题】:Retain/release of returned objects保留/释放返回的对象
【发布时间】:2011-10-27 22:07:48
【问题描述】:

我是 Objective-C 的新手,所以这可能是一个愚蠢的问题。

我不禁看到 ObjC 和 Microsoft 的 COM 在内存管理方面的相似之处(AddRef/Release vs retain/release)。在 COM 环境中,在将对象返回给调用者之前,您或多或少都必须始终使用 AddRef (retain) 一个对象。从我目前看到的情况来看(我是 Cocoa® Programming for Mac® OS X (3rd Edition) 的第三个),内存管理部分有些模糊。

假设没有GC,返回对象的惯用方式是什么?

【问题讨论】:

    标签: objective-c memory-management retain


    【解决方案1】:

    阅读Memory Management Programming Guide 了解自动释放池。

    在 Objective-C 中,按照惯例,对象应该以自动释放的方式返回(除非返回对象的方法的名称以“alloc”、“new”、“copy”或“mutableCopy”开头)。自动释放的对象由 Objective-C 在池中跟踪并自动处理,这意味着您无需关心向它们发送最终版本。与 COM 相比,这极大​​地简化了引用计数,这就是为什么您在大多数时间都看不到对返回对象的任何 release 调用。相反,相同的约定规定由名称以 alloc、new、copy 或 mutableCopy 开头的方法返回的所有对象都由方法调用者负责。您必须在这些对象上手动调用 release,否则您的程序会出现内存泄漏。

    【讨论】:

      【解决方案2】:

      Cocoa 通过引入第三个兄弟来绕过 COM 中 AddRef/Release 的限制; autorelease.

      • retain - 我需要这个,让它坚持下去。
      • release - 我不再需要这个了,你可以立即删除它。
      • autorelease - 我不需要这个,但让它停留几秒钟,以防其他人想先拿起它。

      这个微小的添加允许大多数返回值是处理就像我们有垃圾收集。如果您对保留返回值不感兴趣,则无需执行任何额外操作。

      为了让它工作,有一个约定(一个足够好的约定,可以让编译器在即将到来的 ARC 中自动为你做内存工作)

      • 以这些必须开头的方法名称返回保留的实例:
        • alloc
        • copy
        • new
        • retain
      • 所有其他必须返回自动释放的实例。

      如何在实践中应用它的三个示例实现:

      -(NSString*)newHelloWorldString {
          NSString* s = [NSString stringWithString:@"Hello world"];
          // Apply retain because s in now autoreleased
          return [s retain];
      }
      
      -(NSString*)helloWorldString {
          NSString* s = [[NSString alloc] initWithString:@"Hello world"];
          // Apply autorelease because s is now retained.
          return [s autorelease];
      }
      
      -(NSString*)fullName {
          // No memory management needed, everything is autoreleased and good.
          NSString* fn = [self firstName];
          NSString* ln = [self lastName];
          NSString* s = [NSString stringWithFormat:@"%@ %@", fn, ln];
          return s;
      }
      

      【讨论】:

        【解决方案3】:

        一般是这样的

        return [对象自动释放];

        你可以保留在另一端。

        如果您计划在 Lion/iOS5 上部署或使用最新的 SDK,那么还请查看 ARC。

        【讨论】:

        • 我刚刚开始玩 XCode,我只是把它作为一种爱好,所以我不会在不久的将来部署任何东西 :D。如果我可以问一下,ARC 是什么?
        • 这就是 Cocoa 库顺便返回它们的对象的方式吗?
        • ARC = 自动引用计数。根据商定的模式,构建步骤会自动插入保留/释放。
        • 通常你应该返回一个自动释放的对象。打电话给return [object autorelease]; 时要小心,因为我很少发现自己在构建这样的代码。不要只是盲目地对你的返回值进行自动释放;阅读内存管理指南并了解您在做什么。
        【解决方案4】:

        基本上我会建议让接收它的类保留它。即类 stackoverflow 接收对象答案。

        -(void) setAnswer:(Answer*) _answer{
            self.answer = _answer; // If the answer is created from a returned message.
            [_answer release];
        }
        

        编辑:我想我可能放错了东西,因为我第二次看它。大致意思:

        Answer *_answer = [stackoverflow createAnswer];
        self.answer = _answer;
        [_answer release];
        

        【讨论】:

        • 另一个不好的答案 XD。您不应该释放作为参数传递给您的方法的对象。请停止发布此类答案,以免使新手感到困惑。
        • 请解释为什么你不能在这里发布它,因为你可能会遇到什么问题。启发我。
        • 你只应该释放你创建的对象。传递给您的方法的参数不是在您的方法内部创建的,因此您不应释放它们。这将导致在您的方法的调用者释放(或向其发送任何消息)他发送给您的参数时“发送到已释放实例的消息”。
        • 但是 self.answer 将其加 1 然后基本上释放它,该类成为所有者 + 1,因为发件人已经在那里获得了 +1。
        • 没关系,那是完全不同的项目。问题出在您不应该发布的参数中。再次阅读内存管理指南。有很多事情你需要了解。 developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/…
        【解决方案5】:

        如果您返回一个对象,则由所有者保留它,我会尽可能避免自动释放,因为一旦 nspool 启动,这些对象就消失了,如果它们仍然被使用,就会导致问题。

        即 Answer *answer = [stackoverflow getAnswer] 并且如果在 getanswer 方法中创建了答案,则检索它的人负责释放它。

        有道理吗?

        【讨论】:

        • 如何避免自动释放要返回给调用者的对象?您是否调用 [retain] 并使调用者成为所有者(即使您没有被称为 alloc 或 new)?或者你根本不[保留]对象?
        • 绝大多数方法应该返回一个自动释放的对象。 “尽可能避免自动释放”的建议是不好的建议。
        • 我仍然坚持我所说的,避免返回自动释放的对象。这在 iphone 设计指南中已被无数次提及。例如,如果您要从 coredata 返回一些东西,您不只是返回一个自动释放的对象。这将一直保留在内存中,直到池启动,如果您没有在所有者中正确保留它,您会遇到内存问题,如果是这样,您有一个自动释放的对象没有做任何事情....
        • 这是一个糟糕的建议:它与所有传统的 Objective-C/Cocoa 代码完全相反。
        • 苹果指南规定:减少对自动释放对象的使用。使用 autorelease 方法释放的对象会一直保留在内存中,直到您明确耗尽当前的自动释放池或直到下一次围绕事件循环。如果可以使用 release 方法立即回收对象占用的内存,请尽可能避免使用 autorelease 方法。如果您必须创建适量的自动释放对象,请创建一个本地自动释放池并定期排空它,以便在下一个事件循环之前为这些对象回收内存。
        猜你喜欢
        • 2011-08-29
        • 1970-01-01
        • 1970-01-01
        • 2011-09-19
        • 1970-01-01
        • 2010-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多