我无法在任何地方找到答案。我在Objective-C开发iOS中使用手动内存管理。
我写了一个方便的函数,用于从十六进制字符串中获取UIColor。在其中,它返回
[[UIColor alloc] initWithRed:... alpha:alpha]
显然在某些平台上(我们有一些设备,iOS 8-9范围内),该对象在退出该函数时将被销毁,因此无法使用其返回的UIColor *。现在,我们将其更改为
[[[UIColor alloc] initWithRed:... alpha:alpha] retain]
我的问题是,当我使用此对象时,是否必须将其释放两次?一旦用于保留,一次用于保留?这对我来说似乎很奇怪,我无法在任何地方找到它。
如果我不保留,那么退出该功能(在某些平台上)会使该功能失效。如果我保留,我需要在完成后发布两次?
编辑:
" ...,通常保证在收到的方法或功能中保持有效。如果您希望它在该范围之外保持有效,则应保留或复制它。 "
所以我没有做任何与众不同的事情。文档说我应该保留它"如果"我希望它能超越"功能的范围。我将尝试@FreeNickname建议的内容。这是最有意义的。
答案 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 )非常适合分析手动引用计数代码并识别的问题。
在对您的问题进行编辑时,您引用了文档:
如果您从程序中的其他位置收到某个对象,通常会保证它在收到的方法或函数中保持有效。如果您希望它在该范围之外保持有效,则应
retain
或copy
它。如果您尝试释放已经解除分配的对象,则程序崩溃。
这并不是说您的便利初始化程序应该发出retain
或copy
。如上所述,调用colorWithHexString
的代码负责建立自己对通过UIColor
或retain
返回的copy
对象的所有权声明。
答案 1 :(得分:0)
我认为您正在寻找autorelease的概念,这种概念在您的情况下使用。它本质上是一种向新创建的对象发送延迟release
消息的方法,因此如果需要,调用者有机会retain
,否则在处理autoreleasepool
时会被销毁。
答案 2 :(得分:0)
你"误解了" Apple的文档,因为本主题完全错误。您真的应该阅读有关ARC而不是Apple的文档,因为clang的ARC文档正确解释了MRC与其进行交互。
让我们仔细看看:
您拥有通过为其分配内存或复制它而创建的任何对象。
相关方法:
alloc
,allocWithZone:
,copy
,copyWithZone:
,mutableCopy
,mutableCopyWithZone:
...
相反,如果您不是某个对象的创建者并且没有表达所有者权益,则不得将其释放。
...
如果您在程序中从其他地方收到一个对象,通常会保证它在收到的方法或功能中保持有效。
认真对待此文档,您不是对象的所有者:
[[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:
copy
,copyWithZone:
)
mutableCopy
方法必须返回可保留的对象指针类型。(Apple:mutableCopy
,mutableCopyWithZone:
)
new
方法必须返回可保留的对象指针类型。 (Apple:哎呀,我忘记了什么)
init
方法必须是实例方法,并且必须返回Objective-C指针类型。 ...(Apple:Oooops,我忘记了什么)(5)
因此,您从-init
获得的内容已经保留,您拥有所有权,并且绝对没有理由保留它。
根据Rob的回答,可能有理由 autorelease 。