【问题标题】:Do we have to retain object returned by a method in non-ARC?我们是否必须保留非 ARC 中方法返回的对象?
【发布时间】:2014-01-13 19:22:04
【问题描述】:

考虑在手动保留释放中实现的情况,其中我有一个指向方法返回的对象的变量。

{
    ...
    NSString *str = [self myNewString];
    ...
}

- (NSString *)myNewString
{
    NSString *myString = [NSString stringWithFormat:@"%d-String", 1];
    return myString;
}

这里我们是否必须保留myNewString返回的对象,以便在我们使用它时它不会被释放?

请帮助我是 Objective-C 的新手。提前致谢。

【问题讨论】:

  • 如果您只是在学习 Objective-C,请改为学习 ARC。手动引用计数只是您可能出错的另一件事,它绝对不会给您带来任何好处。
  • 是的,谢谢你的建议。但我热衷于了解幕后实际发生的事情。于是我开始学习手动引用计数。
  • 您希望深入了解 Objectivr-C,这是令人钦佩的,但我会再次敦促您学习现代 Objective-C/ARC。它强调对象之间的关系,而不是机械和自动化的引用计数。
  • 我刚开始时也想学习手动引用计数,直到我编写了我的第一个 ARC 程序,我意识到我浪费了所有花在学习引用计数上的时间。我能做的就是劝你不要犯同样的错误。
  • @godel9:了解 MRC 非常有用。在 ARC 中,编译器只是自动执行 MRC 内存管理规则。这意味着它与 MRC 中遇到的问题相同,例如保留周期。

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


【解决方案1】:

在这里,您只传递了存储 NSString 对象的位置地址。因此,编译器肯定会保留对象。但你不必担心。一旦引用计数为 0,ARC 将负责释放内存。 给你Learn more about ARC

【讨论】:

  • 嗨,我已经编辑了我的问题。我在使用手动引用计数而不是 ARC 时的情况。谢谢。
  • 是的.. 在这种情况下,您不需要保留它,因为不会有任何 ARC 来清除它。但是您必须在不必要时立即释放它。请通过我提供的链接。帮助我了解了我在 ARC 顶层不知道的微小细节
  • 嘿..我不明白你为什么接受其他答案..正如你所说你正在寻找手动参考计数..其他答案谈论 ARC..请再次验证并让我知道如果我错了
【解决方案2】:

除了new/alloc+init 之外,基本上任何返回新对象的方法都没有所有权返回它,这意味着您可以指望它一直存在直到封闭的自动释放池耗尽,但在那之后就不知道了。如果您想保留更长时间,则必须保留它。

【讨论】:

  • 抱歉,此答案对手动引用计数无效。正如问题中明确提到的那样,人们正在谈论手动引用计数。
  • @achievelimitless 如果您认为这个答案没有用或明显错误,您应该投反对票,而不是将其标记为“不是答案”。
  • 对不起@jack.. 没有足够的声望来否决它:(
  • @achievelimitless 这个答案确实适用于 MRC,而不是 ARC。你认为它到底有什么不正确的地方? stringWithFormat 返回一个 autoreleased 字符串。一切都包含在运行循环中的自动释放池中,并且对象将一直存在,直到调用方法返回后该池被耗尽。
  • 你忘了copymutableCopy
【解决方案3】:

这个答案有两个方面:

  1. 首先,您要遵守方法命名规则,该规则规定名称以“alloc”、“new”、“copy”或“mutableCopy”开头的任何方法都应具有 +1 保留计数(即所有权被转移),否则它应该是一个autorelease对象(或者,更准确地说,任何所有权未转移的对象,如果调用者想要声明所有权,则必须手动retain它)。

    顺便说一句,ARC 使用这些方法名前缀来自动确定对象的内存语义,但是在手动保留和释放 (MRR) 代码中,确保方法的内存管理符合方法名称隐含的语义。如果您在将来某个日期将此 MRR 代码与 ARC 代码集成,那么遵循此方法命名规则将变得很重要。如果您有违反此方法命名约定的遗留代码,您可以使用代码提示,但最好确保您的代码的内存语义符合此方法命名规则。

    无论如何,此方法命名规则包含在高级内存管理编程指南中概述的Basic Memory Management Rules 中。

    因此,在手动保留和释放中,您有两种选择之一。如果方法以“alloc”、“new”、“copy”或“mutableCopy”开头,那么它应该通过返回 +1 retainCount 对象来转移所有权,例如:

    - (NSString *)newSomeString
    {
        return [[NSString alloc] initWithFormat:@"%d-String", 1];
    }
    

    否则,它不应该转移所有权(例如返回一个autorelease对象),例如:

    - (NSString *)someString
    {
        return [NSString stringWithFormat:@"%d-String", 1];
    }
    
  2. 所以,如果调用者想确保对象被保留,它可以只调用返回 +1 对象的方法:

    NSString *string = [self newSomeString];
    

    或者,调用返回autorelease对象的版本,然后显式地retain它:

    NSString *string = [[self someString] retain];
    

在实践中,后一种约定,someString 示例更常见(使用返回autorelease 对象的方法,即方法名称​​不以“alloc”开头,“ new”、“copy”或“mutableCopy”;然后如果调用者需要retain它,它应该明确地这样做)。 newcopymutableCopy 方法通常都在各自非常具体的上下文中使用,此处不适用。

顺便说一句,如果您通过静态分析器(Xcode 的“产品”菜单上的“分析”)运行代码,它会在您的 MRR 代码存在过度保留对象或未能保留的问题时发出非常好的警告他们。

但最重要的是,请仔细遵循basic memory management rules,包括命名方法的约定,然后如果您需要保留它,请明确retain 您的autorelease 对象或调用返回+1 的方法retainCount对象。

【讨论】:

  • 这让我更清楚了。如果我使用 alloc 创建了字符串,我不需要在接收时保留它。但是,如果我使用任何类方法(如 stringWithFormat)创建它,我将不得不保留它以确保它在我需要它之前一直存在。我做对了吗@Rob?
  • @user3008132 是的,这基本上是正确的。并且还要确保你的方法的名称与返回的对象的类型相匹配(例如,如果它返回使用alloc创建的+1对象,则使用“alloc”、“new”、“copy”或“mutableCopy”开始方法名称/init; 如果您返回一个autorelease 对象,例如使用stringWithFormat 创建的对象,请不要使用这四个字符串之一启动该方法。在这种情况下,我建议使用一个名为someString(或其他)的方法,该方法返回一个使用stringWithFormat 创建的对象,并让调用者手动retain 它。
  • 非常感谢。这对我帮助很大。
  • "任何名称以“alloc”、“new”、“copy”或“mutableCopy”开头的方法都应该有一个+1的保留计数”你忘了retain
  • "否则,它应该返回一个自动释放的对象" 它不必是自动释放的。它只需要没有 +1 保留语义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-29
  • 1970-01-01
相关资源
最近更新 更多