Cocoa为什么我必须保留并释放一个函数参数?

时间:2009-05-17 20:13:12

标签: objective-c cocoa macos

我正在研究Aaron Hillegass的书,特别是彩票的例子。我对-setEntryDate:方法有疑问;为什么我要保留date?该程序仍然有效,但不保留它。

 -(void)setEntryDate:(NSCalendarDate *)date {
    [date retain];
    [entryDate release];
    entryDate = date;
}

但这仍然可行:

-(void)setEntryDate:(NSCalendarDate *)date {
    entryDate = date;
}

那么为什么我必须保留date然后释放entryDate呢?

4 个答案:

答案 0 :(得分:7)

它现在有效,但是如果你正在编写一个更大的程序,那么在将来某个不确定的点上,对象date指向的对象可能被称为setEntryDate的任何人释放。如果发生这种情况,它将在整个程序的其余部分失效。您将在类中保留此对象,因为该类现在拥有对该对象的引用,并需要指明该对象。通过这样做,即使任何名为setEntryDate的类要释放date,您的类仍将保持对它的有效引用。此外,这不仅仅是您正在编写的常规旧方法。这是一个setter,它负责在它所属的类上设置一个实例变量。如果您正在编写非setter方法,则可能不必保留参数。我想说的是保留方法参数并不总是必要的;它只是在这种情况下(几乎所有的setter都处理非原始类型)。

这称为“引用计数”,并详细解释here。现在,既然你刚开始学习,不要担心阅读。当您开始使用内存管理进入更复杂的场景时,该指南是非常有价值的阅读材料。

答案 1 :(得分:3)

因为您声明对象的所有权,retain就是这样做的。不正确的代码有时会发生正常工作,但这基本上只是运气。

请参阅the Cocoa memory management rules

答案 2 :(得分:1)

这些方法称为访问器方法。顾名思义,它们允许检索和设置变量 - 具体来说,它们被称为“getters”和“setter”。

约定(然而,您将在本书的后续章节中看到的不仅仅是约定)是为变量调用“getter”,例如,NSString称为foo

- (NSString*)foo;

和“二传手”:

- (void)setFoo:(NSString*)newFoo;

在上面的示例中,实现该方法以设置新的日期值。内存管理在第4章中描述,但简而言之,Objective-C对象的工作方式是它们具有“保留计数” - 这表示对象具有的引用数量;在分配时,对象的保留计数为1.然后可以向对象发送retainrelease消息,以分别增加或减少保留计数。 retain消息意味着发送消息的对象想要使用该对象,因此retain是它。 release消息意味着发送消息的对象不再想要使用该对象,因此减少了保留计数。当对象的保留计数达到0时,将释放该对象。这样就避免了内存泄漏。

保留date并释放entryDate的原因是date是您想要“了解”的新对象;因此,您retain要求对其拥有所有权。 entryDate变量指向当前日期对象,但由于您将其设置为新值,因此您不再需要了解它;因此你release;这可以防止内存泄漏,因为您最初会保留此变量。

正如我之前所说,一旦阅读第4章:内存管理,这个概念就会变得更加清晰。现在,只要接受它,并在解释它时理解其背后的原因。

答案 3 :(得分:1)

如果你通过视频更好地学习,斯坦福大学有published一些关于iPhone开发的视频,这些视频在某种程度上也涵盖了Cocoa和Objective C.查看讲座3,它通过示例和讨论对内存管理进行了很好的概述。