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

时间:2011-08-31 19:21:27

标签: objective-c ios

fellow StackOverflow user告诉我,在发布属性时我不应该使用getter方法:

@property(nonatmic, retain) Type* variable;
@synthesize variable;

// wrong
[self.variable release]; 

// right
[variable release]; 

他没有详细解释原因。它们看起来和我一样。 My iOS book说房产的吸气剂看起来像这样:

- (id)variable {
    return variable;
}

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

4 个答案:

答案 0 :(得分:13)

对于没有自定义访问者的保留属性,您可以通过以下方式释放对象:

self.variable = nil;

这具有将ivar(如果只声明属性可能不被称为'变量')设置为nil并释放先前值的效果。

正如其他人所指出的那样,要么直接释放ivar(如果可用),要么使用上面的方法就可以了 - 你不能做的就是从getter返回的变量上调用release。

答案 1 :(得分:9)

您可以选择编写自定义getter行为,这可能会导致完全不同的行为。因此,您不能总是假设[variable release][self.variable release]具有相同的结果。

同样,您可以编写自定义属性,而无需使用独有的ivar支持它们......如果您开始从getter返回的引用中释放对象,它可能会变得很乱!

可能还有其他原因让我不知道......

答案 2 :(得分:4)

典型的吸气剂看起来更像是这样:

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

因此,如果您使用[self.variable release],那么当您只想释放该对象并导致该对象被释放时,您还需要一个额外的retainautorelease迟于必要时(自动释放池耗尽时)。

通常情况下,您可以使用self.variable = nil,这样做的好处是它还可以将变量设置为nil(避免因悬空指针而导致崩溃),或者[variable release]这是最快的如果您的setter具有自定义逻辑,则可能更适合dealloc方法。

答案 3 :(得分:4)

并非所有的吸气者都采用这种形式:

- (id)variable { return variable; }

......这只是最原始的形式。单独的属性应该建议更多的组合,这会改变实现。上面的原始访问器不考虑与内存管理,原子性或复制语义一起使用的习语。在子类覆盖中,实现也很脆弱。

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

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

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

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

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

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

- (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];
    }
}

未能遵循这些简单的规则会使您的代码难以维护和调试,并且难以扩展。

所以缺点是你想让你的程序易于维护。直接在属性上调用release需要您知道该类内部工作的大量上下文;这显然很糟糕,并且错过了良好的OOD的强烈理想。

它还希望作者/子类/客户确切地知道类如何偏离惯例,这在问题出现时是愚蠢和耗时的,并且当问题出现时你必须重新学习所有内部细节(他们将在某些时候)

这些是关于如何在属性结果上调用release会引入问题的一些简单示例。许多现实世界的问题更加微妙,难以找到。