【问题标题】:Returning object initialized through "convenience constructor"返回通过“便利构造函数”初始化的对象
【发布时间】:2009-08-12 14:54:56
【问题描述】:

当实例方法返回一个使用便利构造函数初始化的值时,我是否需要保留该对象,然后在返回中自动释放,以便在便利构造函数的自动释放发生时,它不会删除该对象。

此版本描述是否会在调用代码之前并通过保留或其他方式取得所有权?

- (NSStringMutable *)test {
    NSMutableString *description = [NSMutableString stringWithString:@"Test Value"];
    return description;
}

还是应该这样?

- (NSStringMutable *)test {
    NSMutableString *description = [NSMutableString stringWithString:@"Test Value"];
    [description retain];                               
    return [description autorelease];
}

调用代码:

NSMutableString *testVar = [[NSMutableString alloc] initWithString:[object description]];

【问题讨论】:

    标签: objective-c memory-management initialization return-value autorelease


    【解决方案1】:

    不,你应该没问题:

    - (NSStringMutable *)test
    {
        return [NSMutableString stringWithString:@"Test Value"];
    }
    

    这将使保留计数为 1 的对象保留在自动释放池中。

    自动释放池在特定时间耗尽 - 它不像垃圾收集器。如果您正在实现事件处理程序(如按钮单击处理程序),当您从事件处理代码返回时,自动释放池会被框架耗尽。

    如果你用过这个:

    - (NSStringMutable *)test
    {
        NSMutableString *description = [NSMutableString stringWithString:@"Test Value"];
        [description retain];                                                               
        return [description autorelease];
    }
    

    ...那么该对象的保留计数为 2 并且会在自动释放池中两次,并且实际上的行为方式与前面的代码示例中的相同。

    【讨论】:

    • 你是对的,但尽量避免谈论保留计数,它们是一个红鲱鱼 - 没有保证 NSMutableString 将返回一个自动释放的对象,只是它返回一个你不返回的可变字符串目前拥有。您可以安全地将结果返回给调用者,因为内存管理规则明确表示“该方法也可以安全地将对象返回给它的调用者”。 developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/…>
    • 这很好。我发现考虑保留计数有助于解释事情。你是对的 - 你只知道 stringWithString 返回一个由其他人拥有的对象。在这种情况下,由于 NSMutableString 实际分配了对象,因此释放它是 NSMutableString 的责任。不过,我的印象是,这些便利构造函数(非初始化构造函数)通常会返回自动释放的对象。如果我遇到一个不这样行事的人,我会感到惊讶。
    【解决方案2】:

    你可以退货。这是自动释放的主要目的之一。除非您设置了自己的自动释放池,否则池在下一次运行事件循环之前不会被耗尽。 memory management programming guide 详细解释了这一切——你应该阅读它,直到你觉得舒服为止。

    旁注:如果这个安全,并且自动释放池由于某种奇怪的原因会提前耗尽,那么给它两个保留和两个自动释放不会有什么不同。数字仍然是平衡的,所以它仍然会在某个时候被释放出来。

    【讨论】:

      【解决方案3】:

      我已经对正确答案进行了投票,我将其添加为样式注释:

      您的调用代码不起作用,因为它在调用 [object description] 时应该调用 [object test]

      除非您真的希望能够更改字符串,否则您不需要返回可变字符串。我个人尽量减少我编写的代码中的可变性,因为我觉得维护状态变化最小的程序更容易。您只返回一个描述,所以我认为它不需要是可变的。 我知道这只是一些示例代码,所以也许我太挑剔了

      您可以将其重写为:

      -(NSString *)description {
          // Just return a static NSString. No need to worry about memory management.
          return @"Test Value";
      }
      

      如果您希望能够在调用代码中更改此返回字符串的值:

      NSMutableString *testVar = [[NSMutableString alloc]initWithString:[object description]];
      

      由于您已对该字符串调用 alloc,因此您拥有它并负责在未来某个日期释放它。

      或者,您可以使用我最喜欢的代码之一:

      NSMutableString *testVar = [[object description] mutableCopy];
      

      这将返回一个不可变对象的可变副本(当然,如果它符合 NSMutableCopying 协议)。您需要在某个阶段发送[testVar release]

      并将其作为您问题的实际答案:如果您发送 alloccopymutableCopy保留 到一个对象,然后您拥有该对象并负责向它发送 release 消息。你可以假设其他任何东西都会返回一个自动释放的对象。

      再说一次,我知道这只是您提出问题的一小段示例代码,但如果您遵循上述规则,您的大部分内存管理问题都会得到解决。在您的第一个示例中,您没有发送任何这些消息,因此您不需要自己释放任何内存。但是,您的调用代码中有一个alloc,因此您拥有testVar,您需要释放它。

      【讨论】:

      • 感谢您的意见。我不知道 mutableCopy。你是对的,这只是我的问题的一个例子。感谢您的详细说明。我对目标 c 相当陌生,即使返回一个 NSString,我也没有将它传递给一个 NSMutableString 的 initWithString。感谢您的信息。
      【解决方案4】:

      不,您可以简单地返回自动释放的值。这样做的原因是 autorelease 不是变量本身的函数,它是 autorelease 池的函数,它(除非你自己创建一个)通常由运行循环管理。

      【讨论】:

        【解决方案5】:

        您与第二个很接近,但是对于您在这里谈论的情况,您不需要保留,实际上也不需要自己调用 autorelease。

        这是有效的,因为 stringWithString 将返回一个自动释放的对象:

         - (NSStringMutable *)test
         {
           return [NSMutableString stringWithString:@"Test Value"];        
         }
        

        一般来说,使用 Objective-C 创建对象时,如果您调用便利构造函数(而不是调用 alloc 和 init),则返回值始终是自动释放的,因此 stringWithString 返回一个自动释放的对象,您可以直接返回。

        【讨论】:

          猜你喜欢
          • 2023-03-31
          • 2012-03-05
          • 2012-09-15
          • 1970-01-01
          • 2017-06-23
          • 1970-01-01
          • 2018-05-10
          • 2015-01-05
          • 2019-06-03
          相关资源
          最近更新 更多