需要发布两次?

时间:2016-06-04 15:26:30

标签: objective-c memory-management manual-retain-release

我无法在任何地方找到答案。我在Objective-C开发iOS中使用手动内存管理。

我写了一个方便的函数,用于从十六进制字符串中获取UIColor。在其中,它返回

[[UIColor alloc] initWithRed:... alpha:alpha]

显然在某些平台上(我们有一些设备,iOS 8-9范围内),该对象在退出该函数时将被销毁,因此无法使用其返回的UIColor *。现在,我们将其更改为

[[[UIColor alloc] initWithRed:... alpha:alpha] retain]

我的问题是,当我使用此对象时,是否必须将其释放两次?一旦用于保留,一次用于保留?这对我来说似乎很奇怪,我无法在任何地方找到它。

如果我不保留,那么退出该功能(在某些平台上)会使该功能失效。如果我保留,我需要在完成后发布两次?

编辑:

https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/MemoryManagement.html

" ...,通常保证在收到的方法或功能中保持有效。如果您希望它在该范围之外保持有效,则应保留或复制它。 "

所以我没有做任何与众不同的事情。文档说我应该保留它"如果"我希望它能超越"功能的范围。我将尝试@FreeNickname建议的内容。这是最有意义的。

3 个答案:

答案 0 :(得分:2)

你说:

  

我写了一个方便函数,用于从十六进制字符串中获取UIColor。在其中,它返回

[[UIColor alloc] initWithRed:... alpha:alpha]

根据Basic Memory Management Rules,正确的内存管理由您的方法名称决定:

  • 如果您的方法名称不是以“alloc”,“new”,“copy”或“mutableCopy”开头,那么您应该返回一个autorelease对象:

    - (UIColor *)colorWithHexString:(NSString *)hexString {
        ...
        return [[[UIColor alloc] initWithRed:... alpha:alpha] autorelease];
    }
    
  • 如果您的方法名称以“alloc”,“new”,“copy”或“mutableCopy”开头,那么您可以返回上面的对象:

    - (UIColor *)newColorWithHexString:(NSString *)hexString {
        ...
        return [[UIColor alloc] initWithRed:... alpha:alpha];
    }
    

    请注意,此模式不如上述colorWithHexString惯例。

(注意,这种由方法名称前缀决定的内存管理在历史上仅仅是最佳实践,但现在,为了与ARC代码的互操作性,它至关重要。始终遵循手动引用计数代码中的上述规则。)

现在,如果调用您的便利初始化程序的代码允许取消分配该对象,则问题在于该代码,而不是您的便利初始化程序。不要开始向初始化程序添加额外的retain语句,因为调用它的内容无法正确管理其内存。

相反,请确保调用代码对retain本身的结果执行正确的release(最终colorWithHexString)。

顺便说一句,Xcode的静态分析器( shift + 命令 + B )非常适合分析手动引用计数代码并识别的问题。

在对您的问题进行编辑时,您引用了文档:

  

如果您从程序中的其他位置收到某个对象,通常会保证它在收到的方法或函数中保持有效。如果您希望它在该范围之外保持有效,则应retaincopy它。如果您尝试释放已经解除分配的对象,则程序崩溃。

这并不是说您的便利初始化程序应该发出retaincopy。如上所述,调用colorWithHexString的代码负责建立自己对通过UIColorretain返回的copy对象的所有权声明。

答案 1 :(得分:0)

我认为您正在寻找autorelease的概念,这种概念在您的情况下使用。它本质上是一种向新创建的对象发送延迟release消息的方法,因此如果需要,调用者有机会retain,否则在处理autoreleasepool时会被销毁。

答案 2 :(得分:0)

你"误解了" Apple的文档,因为本主题完全错误。您真的应该阅读有关ARC而不是Apple的文档,因为clang的ARC文档正确解释了MRC与其进行交互。

让我们仔细看看:

  

您拥有通过为其分配内存或复制它而创建的任何对象。

     

相关方法:allocallocWithZone:copycopyWithZone:mutableCopymutableCopyWithZone:

     

...

     

相反,如果您不是某个对象的创建者并且没有表达所有者权益,则不得将其释放。

     

...

     

如果您在程序中从其他地方收到一个对象,通常会保证它在收到的方法或功能中保持有效。

认真对待此文档,您是对象的所有者:

[[UIColor alloc] initWithRed:... alpha:alpha]

这是因为你+alloc等人那里接收了对象引用,但是来自-init…。根据Apple的文档,您不是所有者,必须保留它。 (所以它是"其他地方"。)

在clang的文档中,described differently and correctly

  

init系列中的方法隐式使用其self参数,返回保留的对象。(5.2.1)

因此,-init…有一个特殊的方法系列,以及Apple的文档中提到的其他系列correctly described in clang's documentation

  

家庭及其增加的限制是:

     
      
  • alloc方法必须返回可保留的对象指针类型。 [Apple:alloc,allocWithZone:)

  •   
  • 复制方法必须返回一个可保留的对象指针类型。 [Apple:copycopyWithZone:

  •   
  • mutableCopy方法必须返回可保留的对象指针类型。(Apple:mutableCopymutableCopyWithZone:

  •   
  • new方法必须返回可保留的对象指针类型。 (Apple:哎呀,我忘记了什么)

  •   
  • init方法必须是实例方法,并且必须返回Objective-C指针类型。 ...(Apple:Oooops,我忘记了什么)

  •   
     

(5)

因此,您从-init获得的内容已经保留,您拥有所有权,并且绝对没有理由保留它。

根据Rob的回答,可能有理由 autorelease