Setter:[价值复制]还是[价值发布]?

时间:2009-09-02 15:33:40

标签: objective-c memory

我对下面两个例子中的最后几行感到有点好奇(即planetName = [value ??????])我的理解是第一个带有副本的例子是最好的,因为它需要副本用于防止原始字符串对象在其他位置更改的字符串对象。

我也对第二个例子中的最后一行感到有些困惑,我的理解是,值对象被传递到方法中,我想我很困惑,因为值被保留而没有相关的释放?有人可以让我直截了当吗?

- (void)setPlanetName:(NSString *)value {
    if (planetName != value) {
        [planetName release];
        planetName = [value copy];
    }
}

- (void)setPlanetName:(NSString *)value {
    if (planetName != value) {
        [planetName release];
        planetName = [value retain];
    }
}

2 个答案:

答案 0 :(得分:1)

假设:

- (void)setPlanetName:(NSString *)value {
    if (planetName != value) {
        [planetName release];
        planetName = [value copy];
    }
}

-copy确保如果有人将NSMutableString的实例作为value传入,则planetName不会在您的实例中从您的下方更改。

良好的防御性编程模式。请注意,-copy在不可变字符串上是免费的; -copy只是碰撞保留值并返回self(已复制的字符串的实例)。

现在,考虑你的第二个例子:

- (void)setPlanetName:(NSString *)value {
    if (planetName != value) {
        [planetName release];
        planetName = [value retain];
    }
}

完全有效且工作正常,而不是防御性。

在这两种情况下,必须使用planetName方法发布-dealloc

- (void) dealloc
{
    [planetName release];
    planetName = nil; // defensive
    [super dealloc];
}

如果字符串被复制,保留,或者最初是传递给setter的常量字符串,则无关紧要。如果您保留它(或暗示通过副本保留它),您必须将其保留。

请注意,您可以将其视为“转义模式”。只要planetName的现有值逃脱您的对象,您必须释放它。当对象被释放或设置了一个新的planetName值时,就会发生这种情况,因此在setter中释放。

或者,如果在Mac OS X上,您可以打开垃圾收集并完成它。无论如何,你应该使用@property& @synthesize自动生成getter / setter对。

答案 1 :(得分:0)

在类的dealloc方法中,应该有另一个[planetName release],它将处理任何实例变量的释放。如果存在,则无需担心内存泄漏。

至于你的另一个问题,如果你有一个可变对象,你不想让其他代码能够修改你的类所期望的东西,那么就会使用yes拷贝。您应该释放您调用copy的任何对象,因为它返回保留计数为1的内容。此外,在不可变对象(如NSStrings与NSMutableStrings)的情况下,复制只调用retain,因为不需要make不可变的东西的完整副本。