自动释放对象的保留/复制

4

我希望确保我正确理解了内存管理。在这里使用其中一种assignCurrentDate方法是否有特殊原因?此外,所有这些方法都不会导致内存泄漏,对吗?

在.h文件中,我们有:

NSDate *currentDate1;
NSDate *currentDate2;
NSDate *currentDate3;
NSDate *currentDate3; 
//and 
@property (nonatomic, retain) NSDate *currentDate1;
@property (nonatomic, retain) NSDate *currentDate2;
@property (nonatomic, retain) NSDate *currentDate3;
@property (nonatomic, retain) NSDate *currentDate4;

在 .m 文件中:

-(void) assignCurrentDate1
{
currentDate1 = [[NSDate date]retain];
//[NSDate date] is autoreleased
}

-(void) assignCurrentDate2
{
currentDate2 = [[NSDate date]copy]; 
}

-(void) assignCurrentDate3
{
self.currentDate3 = [NSDate date];
}

-(void) assignCurrentDate4
{
currentDate4 = [[NSDate alloc]init];
//[[NSDate alloc]init] is not autoreleased.
}

-(IBAction) printDate
{
NSLog ("%@", currentDate1);
NSLog ("%@", currentDate2);
NSLog ("%@", currentDate3);
NSLog ("%@", currentDate4);
}

- (void)dealloc
{
[currentDate1 release];
[currentDate2 release];
[currentDate3 release];
[currentDate4 release];
[super dealloc];
}

2个回答

6
iOS内存管理的经验法则是:
每个allocretaincopynew都必须有相应的releaseautorelease
实际上,您在几个地方泄漏了。 在您的标头中,您保留了日期对象,然后在dealloc方法中释放它们。 这是正确的。 然而,在您的assignDate方法中,您没有释放复制或保留的日期。 而[NSDate date]是自动释放的,但您却自己保留和复制它们。
没有理由使用您的assignCurrentDate方法。 您可以在init方法中执行以下操作:
self.currentDate1 = [NSDate date];

就是这样。

编辑:(好吧,那不是全部。)

正如Jim在评论中指出的:

头文件中的retain表示为这些属性合成的setter会保留分配给它们的对象。但是如果您查看assign*方法,您将看到只有assignCurrentDate3实际使用该属性。其余的直接分配给ivar,绕过了合成的setter,因此在分配时不会被保留。


4
补充一下信息:如果您调用 assignCurrentDate1/2/4,就会发生泄漏。只有 assignCurrentDate3 是安全的,因为它调用属性的 setter 方法,会释放存储的值并保留给定的新值。 - marcus
1
这完全不正确。*"在你的头文件中,你保留了你的日期对象"* - 头文件中没有保留任何内容。那些是属性声明。头文件中的retain表示生成的setter会保留分配给这些属性的对象。但是如果你看一下assign*方法,你会发现只有assignCurrentDate3实际上使用了该属性。其余的直接分配给ivar,绕过了生成的setter,因此在分配时不会被保留。 - Jim
1
assignCurrentDate1/2/4 方法在分配新值之前未能释放旧值。如果它们被调用超过一次,它们将会泄漏。新值在所有情况下都被正确地保留。 - albertamg
是的,如果使用超过一次。这是一个样例代码,对比了创建和分配对象的不同方法 - 在我的看来,分离不同情况的方法只是作为一种方式使用,并且它们本身相当无意义。当然,如果你假设这里讨论的是整个方法,那么你不应该这样做,但我没有那种印象 - 谁会写一个仅仅为了分配一个对象的方法呢? - Jim
@Moshe 给出了非常好的答案,谢谢。换句话说:1、2和4不会被setter保留,但由于使用了retain、copy和init,它们的保留计数会增加。如果稍后将新的日期对象分配给这些实例变量,旧的对象将失去指针并永远不会被释放(导致泄漏)。 - Cephi
@Cephi - 听起来没错。(@Jim,如果我错了,请随意纠正。:-D) - Moshe

2
是的,你对内存管理的理解是正确的。假设你不会多次调用这些方法,那么它们都不会泄漏。第二种方式在内存使用方面不太高效,因为会创建两个NSDate实例。实际上,它们在性能方面略有不同,但除非你将它们放入紧密循环中,否则差异不会显著。
从程序设计的角度来看,你不应该编写这样的代码,因为如果你调用1、2或4超过一次,最初分配的实例将会泄漏。如果你确定这不是问题(例如,如果你在viewDidLoad中分配并在viewDidUnload中释放),那么你可以安全地使用任何一种风格,但如果你不确定是否这样的话,你需要在分配之前释放你的赋值,或者你应该使用第三种基于属性的方法,它会自动为你完成这些操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接