可接受的方式释放财产

假设有一个具有以下接口的类:

#import <Foundation/Foundation.h> @interface MyClass : NSObject { } @property (nonatomic, retain) NSDate* myDate; -(void)foo; @end 

并执行以下操作:

 #import "MyClass.h" @implementation MyClass @synthesize myDate = _myDate; - (void)dealloc { [_myDate release]; [super dealloc]; } -(void)foo { NSDate* temp = [[NSDate alloc] init]; self.myDate = temp; [temp release]; } @end 

1)在函数foo将释放像这样确保对象的保留计数被正确地维护(即没有内存泄漏并且没有不必要的释放被执行)。

  NSDate* temp = [[NSDate alloc] init]; self.myDate = temp; [temp release]; 

2)与1)相同的问题,除了适用于以下技术:

 self.myDate = [[NSDate alloc] init]; [self.myDate release] 

3)与1)相同的问题,除了适用于以下技术:

 self.myDate = [[NSDate alloc] init] autorelease]; 

4)与1)相同的问题,但适用于以下技术:

 self.myDate = [[NSDate alloc] init]; [_myDate release] 

5)与1)相同的问题,但适用于以下技术:

 [_myDate release]; _myDate = [[NSDate alloc] init]; 

1)很好。

2)可能不安全,并会在最新的LLVM静态分析仪中触发警告。 这是因为getter方法返回的对象可能与传递给setter的对象不同。 (例如,二传手可能已经做了一个副本,或者可能没有通过validation,而是设置nil )。这意味着你正在泄漏原始对象,并且过度释放吸气者给你的那个。

3)很好; 类似于1,但是当当前的自动释放池被排空而不是立即释放。

4)可能不安全,但不会触发我见过的警告。 这个问题与2中描述的相似; ivar中的对象可能不是你传给二传手的那个。

5)安全,但不会使用安装方法或通知任何观察员的财产。

在属性是retaintypes的情况下,getter和setter都只是合成的版本,所有上面的例子都可以使用。 但是,它们并不都代表最佳实践,并可能触发分析警告。 目标应该是, 无论 myDate如何pipe理其内存, -foo方法都能正常工作。 上面的一些例子并没有这样做。

例如,如果您决定将属性更改为稍后copy ,则不应要求更改任何其他代码以使其正常工作。 在情况2和4中,你被要求改变附加的代码,因为foo方法假定setter将总是成功并且始终设置原始对象。

5)是一个错误 – 它泄漏旧的实例,因为它不会被释放,但只是重新分配。

1)是干净的,最好的方式去。 4)是好的,但是会给内存系统带来一些负担 – 对象可能比需要的活得更长。 2)在技术上没问题,但是你不应该直接保留/释放这个属性 – 这就是语法糖的用处! 3)技术上没问题,但也绕过财产,依靠实施细节。

2)和3)在部分代码改变的时候不鼓励并且要求麻烦。

编辑:新的代码不泄漏在5)。 不过,它也有相同的缺点。

有一个原因,我们得到了财产的支持,并做了一个伟大的和一贯的使用。 你应该只考虑绕过他们,如果你的时间档案给了非常清楚的提示,这是一个瓶颈(不太可能)。

首先,如果你想避免alloc,release,autorelease等等,你可以调用一个不以alloc启动的date工厂方法。

例如:self.myDate = [NSDate date];

date类工厂方法根据约定规则进行自动释放。 然后财产保留它。

  1. Alloc将给它一个保留计数1,然后分配财产将保留它。 既然你的class级现在正在保留它的财产,你可以释放它来反制行为。

  2. 同上,但这是一个奇怪的方式来做到这一点。

  3. 3相当于我上面的代码([NSDate date]);

  4. 在这种情况下,该属性将保留它(在alloc增加保留计数之后),那么你将在下面减去它。 作品,但我不会build议这样做,因为你是合成(保留)财产将为你做。

释放和更新的模式仅仅是一种语义。 你会得到以下每一项的保留数。

 myObject = [Object alloc] objectCopy = [myObject copy] myNewObject = [Object newObjectWithSomeProperties:@"Properties"] // Keyword here being new // And of course [myObject retain] 

具有修饰符(保留)或(副本)的属性将保留在其上。 后台存储_myDate只是实际存储对象的位置。

当你得到一个保留计数,你需要释放。 或者立即使用[myObject release]消息,或者让池使用[myObject autorelease]

无论如何,任何保留你被给予(隐含或显式)将需要被释放。 垃圾收集器不会收集你的对象,你将有一个内存泄漏。

中最常用的用法

 Object myObject = [[[Object alloc] init] autorelease]; // Use this when you dont plan to keep the object. Object myObject = [[Object alloc] init]; self.myProperty = [myObject autorelease]; // Exactally the same as the Previous. With autorelease // Defined on the assignment line. self.myProperty = [[[Object alloc] init] autorelease]; // Same as the last two. On one line. 

我将展示其他的可能性

 // Uncommon. Not incorrect. But Bad practice myObject = [[Object alloc] init]; self.myProperty = myObject; // Options [_myProperty release] // Bad practice to release the instance variable [self.myProperty release] // Better practice to Release the Property; // releasing the property or the instance variable may not work either. // If your property is using the (copy) modifier. The property is copied rather then retained. // You are still given a retain count. // But calling release on a copy will not release the original [myObject release]; // Best Practice. Good when Threading may run the autorelease pool [myObject autorelease]; // As good as the previous. // But may leave your object in memory during long operations 

实质上,给定保留的对象将是属性variables和实例variables中的同一对象。 释放任何一个将释放它。 然而。 最佳实践说,如果你保留一个对象。 最好在该对象的同一个variables上调用release。 即使自动释放和保留被称为另一边。

//其他项目,给你一个保留计数。 核心媒体或核心任何具有创build或复制名称的function。