为什么我不应该使用getter来释放objective-c中的属性?

一个StackOverflow用户告诉我,释放属性时不应该使用getter方法:

@property(nonatmic, retain) Type* variable; @synthesize variable; // wrong [self.variable release]; // right [variable release]; 

他没有详细解释为什么。 他们对我来说也一样。 我的iOS书上说,属性上的getter看起来像这样:

 - (id)variable { return variable; } 

那么这是不是意味着[self variable]self.variablevariable都是一样的?

一个典型的getter看起来更像这样:

 - (id)variable { return [[variable retain] autorelease]; } 

所以如果你使用[self.variable release]你有一个额外的retainautorelease ,当你只想释放这个对象时,你并不需要这个额外的retainautorelease ,并且导致这个对象被释放的时间超过了必要的时间(当autorelease池被释放)。

通常情况下,你可以使用self.variable = nil ,它的好处是它也将variables设置nil (避免由于悬挂指针引起的崩溃),或者是最快速的[variable release] ,在dealloc方法中可能更合适如果你的setter有自定义的逻辑。

对于没有自定义存取器的保留属性,可以通过以下方式释放对象:

 self.variable = nil; 

这具有设置ivar(如果只有声明的属性,可能不会被称为“variables”)的效果,并释放之前的值。

正如其他人指出的,无论是直接释放伊娃(如果可用)或使用上述方法都是可以的 – 你不能做的就是调用释放从一个getter返回的variables。

您可以select编写自定义getter行为,这可能会导致完全不同的行为。 所以,你不能总是认为[variable release][self.variable release]具有相同的结果。

同样,你可以编写自定义的属性,而不需要独家的ivar支持它们…如果你开始从getters返回的引用释放对象,它可以快速地混乱!

可能还有其他原因,我不知道…

并非所有的获得者都采取这种forms:

 - (id)variable { return variable; } 

这只是最原始的forms。 属性本身应该build议更多的组合,这改变了实施。 上面的原始访问器不考虑与内存pipe理,primefaces性或复制语义结合使用的习惯用法。 在子类覆盖中实现也是脆弱的。

一些非常简短的例子, 在实现变得相当复杂的实际程序中事情显然变得更加复杂。

1)getter可能不会返回实例variables。 几种可能性之一:

 - (NSObject *)a { return [[a copy] autorelease]; } 

2)setter可能不保留实例variables。 几种可能性之一:

 - (void)setA:(NSObject *)arg { ... a = [arg copy]; ... } 

3)最终在整个程序中实施内存pipe理,这使得难以维护。 类的语义(以及它如何处理实例variables的引用计数)应保存在类中,并遵循预期结果的约定:

 - (void)stuff:(NSString *)arg { const bool TheRightWay = false; if (TheRightWay) { NSMutableString * string = [arg mutableCopy]; [string appendString:@"2"]; self.a = string; [string release]; // - or - NSMutableString * string = [[arg mutableCopy] autorelase]; [string appendString:@"2"]; self.a = string; } else { NSMutableString * string = [arg mutableCopy]; [string appendString:@"2"]; self.a = string; [self.a release]; } } 

不遵循这些简单的规则会使你的代码很难维护和debugging,并且很难扩展。

所以缺点是你想让你的程序易于维护。 直接在一个属性上调用释放需要你知道类的内部运作的很多上下文; 这显然是糟糕的,错过了很好的OOD理想。

它也期望作者/子类/客户能够准确地知道class级是如何背离约定的,当问题出现时,这是愚蠢和耗时的,当问题出现时(他们会在某个时刻),你必须重新学习所有的内部细节。

这些都是一个简单的例子,如何调用释放财产的结果引入问题。 许多现实世界的问题更加微妙和难以定位。