保留NSArray论点 - 为什么?

时间:2012-02-14 06:05:45

标签: objective-c nsarray retain

我试过看但找不到任何帮助。

- (NSArray *)sushiTypes {
    return _sushiTypes;
}

- (void)setSushiTypes:(NSArray *)sushiTypes {
    [sushiTypes retain];
    [_sushiTypes release];
    _sushiTypes = sushiTypes;
}

我想知道的是,在我工作this教程时,我无法弄清楚为什么他会保留这个论点。我试着评论一下retain语句,程序运行相同,没有泄漏。那只是不必要吗?

我还想补充一个事实,我打电话给这样的方法

self.sushiTypes = [[NSArray alloc]initWithObjects:"objects...];

但是当我调试它时,它不会转到 - (NSArray *)sushiTypes方法,而是转到setSushiTypes方法。这是为什么?

4 个答案:

答案 0 :(得分:4)

您将_sushiTypes指向sushiTypes的值。由于_sushiTypes是一个实例变量,因此您需要保留此对象的所有权。如果你没有这样做,并且该对象的所有其他所有者都会释放它,那么这个内存将被释放,让你的实例变量指向垃圾,你的应用程序就会崩溃。

重要的是要注意setter中消息的顺序。你需要打电话

[sushiTypes retain];

首先,因为_sushiTypes和sushiTypes可能指向同一个对象。如果您将它们翻转并先调用释放,则在您有机会获得所有权之前,可能会释放内存。

答案 1 :(得分:2)

作者保留的原因是因为这是retain属性的标准setter语法。在ObjC中,对象必须保留,除非我们确定某个其他对象将负责保持它(通过保留它)。

当你从setter中删除retain时,事情仍然有效,因为你对setter的调用是错误的。它应该是:

 self.sushiTypes = [[[NSArray alloc] initWithObjects:one, two, three, nil] autorelease];

因为该对象的保留计数为1. Google NARC和objective-c,可能会为您带来here。调用setter 的方法有来释放(或自动释放,更好),因为它很快就会失去这样做的能力而且你会有泄漏。

即使进行了更正,您的setter方法也可以在不保留的情况下工作,因为自动释放会在以后发生。

此setter是使用显式语法从self或其他对象调用set时调用的方法:

 [self setSushiTypes:whatever];

或隐含语法:

 self.sushiTypes = whatever;

注意:即使没有声明self.sushiTypes =,使用@property时也会调用setter。

无论如何,很明显你没有使用ARC,但是使用ARC,大多数问题都会消失。但是,您可能应该完成此练习,因为ARC无法解决所有这些类型的问题。

答案 2 :(得分:0)

是的,更具体地说,它可能会将保留计数初始化为1。

是否与[sushiTypes retain]相同。我知道如果我们调用retain,该对象将一直保留到我们发布之前。

不一样。这将增加保留计数两次。没有太多理由在同一个地方增加两次保留计数。如果你这样做了,你将负责两次调用释放。

你有一个保留的sushiTypes。这个sushiTypes作为参数传递给函数。稍后在函数中你发布了它。它会释放sushiTypes的内存吗?如果是的话,寿司类型不再存在。

首先,您应该确保您了解release是否释放内存取决于是否有其他所有者持有该对象的引用。如果[_sushiTypes release]有多个东西保留了对象,那么在这种情况下释放不会释放内存。

其次,糟糕的主意。为了通过引用计数保持理智,您应该遵循某些模式。

保留(或分配)实例变量,在dealloc或之前释放它们。 如果需要,保留(或分配)局部变量,并在退出方法之前释放它们。 调用者不拥有函数的返回值。这意味着您处理函数返回值,如局部变量,但在返回它之前自动释放它而不是释放它。这确保它将至少持续足够长的时间以便呼叫者保留它,如果需要的话。 其中一个模式不是方法调用者拥有对方法参数的引用,但是当函数返回时,调用者不拥有该引用。该方法不应释放调用者的引用。

继续使用2.1,而不是发布sushiTypes。我创建了一个局部变量NSArray * sushiTypes = _sushiTypes。如果我发布了sushiTypes,它还会发布sushiTypes。或者,如果我保留sushiTypes,它还会保留_sushiTypes。

保留和释放发送到对象,而不是引用。 sushiTypes和_sushiTypes指的是同一个对象,所以它与另一个对象的调用保留或释放相同。

对于[sushiTypes retain]以及稍后在同一方法[_sushiTypes release]中,这是合法的,但可能是不必要的。但是不要只做[sushiTypes release],从而剥夺了_sushiTypes对象的所有权。

答案 3 :(得分:0)

这是一个制定者,我会给你举个例子。 假设您的_sushiTypes ivar指向objA,现在您想将您的ivar设置为一个新对象,例如objB即作为sushiTypes参数传递。

1.然后在你的二传手中保留objB,因为你将它设置为ivar并想拥有所有权。所以你写[sushiTypes retain];

2.然后释放旧对象(因为您将要使用相同的setter保留新对象,即objB到ivar)。因此,您释放了旧对象[_sushiTypes release];,然后将保留的对象分配给_sushiTypes ivar。