如何处理@synthesized retain属性的发布?

在Objective-C中,我有一些关于合成属性的问题。 完整的列表如下,但基本的问题是这样的: 即使我的代码可能包含或不包含dealloc中的发布方法,编译器如何确保合成属性的ivars被正确释放?

注:我决定不把这些问题作为个别问题发布,因为它们之间关系如此密切,还有一些现存的问题涉及到个别问题,而没有真正处理问题的核心问题。

有些类似的问题:

  • 财产保留是否需要发布?
  • 财产和综合有什么区别?
  • 保留属性与属性问题及综合

设置:考虑一个具有单个属性的类:

@interface Person : NSObject { NSString * name; } @property (nonatomic, retain) name; @end 

问题1:非常基本的情况:

 @implementation Person @synthesize name; @end 

通过这个设置,我认为每当一个Person对象被释放时,这个name就会自动释放。 在我看来,编译器只是简单地将[name release]插入到dealloc方法中,就像我自己input了一样。 那是对的吗?


问题2:如果我select为这个类编写自己的dealloc方法,并且省略了对[name release]的调用,那么会泄漏吗?

 @implementation Person @synthesize name; - (void)dealloc { [super dealloc]; } @end 

问题3:如果我select为这个类编写我自己的dealloc方法,并且包含[name release]的调用,那么会导致双重释放,因为@synthesize已经为我处理了它?

 @implementation Person @synthesize name; - (void)dealloc { [name release]; [super dealloc]; } @end 

问题4:如果我select为这个类编写自己的属性访问器,但是我写自己的dealloc方法, name是否会被泄漏?

 @implementation Person @dynamic name; - (void)setName:(NSString *)newName { [newName retain]; [name release]; name = newName; } @end 

问题5:我有一种感觉(基于经验),上述情况都不会导致泄漏或双重排放,因为语言的devise是为了避免这种情况。 当然,这就提出了“如何?”的问题。 编译器是否足够聪明以跟踪每一个可能的情况? 如果我要做以下事情(注意这是一个荒唐的例子,只是为了说明我的观点):

 void Cleanup(id object) { [object release]; } @implementation Person @synthesize name; - (void)dealloc { Cleanup(name); } @end 

这会愚弄编译器添加另一个[name release]dealloc方法?

Q1:

不, -dealloc不会修改你的-dealloc 。 你必须自己发布这个name

Q2:

是的,它会泄漏。 原因与第一季度相同。

Q3:

不,它不会双重释放。 原因与第一季度相同。

Q4:

是的,它会泄漏。 原因与第一季度相同。

Q5:

不,它不会双重释放。 原因与第一季度相同。


你可以通过覆盖-retain-release-dealloc来检查这个-dealloc以报告发生了什么。

 #import <Foundation/Foundation.h> @interface X : NSObject {} @end @implementation X -(oneway void)release { NSLog(@"Releasing %p, next count = %d", self, [self retainCount]-1); [super release]; } -(id)retain { NSLog(@"Retaining %p, next count = %d", self, [self retainCount]+1); return [super retain]; } -(void)dealloc { NSLog(@"Dealloc %p", self); [super dealloc]; } @end @interface Y : NSObject { X* x; } @property (nonatomic, retain) X* x; @end @implementation Y @synthesize x; - (void)dealloc { [x release]; [super dealloc]; } @end int main () { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; Y* y = [[Y alloc] init]; X* x = [[X alloc] init]; yx = x; [y release]; [x release]; [pool drain]; return 0; } 

在Q1,Q2和Q4中, x的最后-retainCount数是1,所以存在泄漏,而在Q3和Q5中,最后的-retainCount为0, -dealloc ,所以没有泄漏。

从属性的Objective-C文档 :

的dealloc

声明的属性从根本上取代了访问方法声明; 当你合成一个属性时,编译器只会创build任何缺less访问器方法。 与dealloc方法没有直接的交互 – 属性不会自动为您释放。 然而,声明的属性确实提供了一种有用的方法来检查dealloc方法的实现:可以在头文件中查找所有属性声明,并确保未标记为assign的对象属性被释放,并且标记为assign的对象属性没有发布。

这基本上回答你所有的问题。

简单和一般的规则:如果你分配,保留或复制一个对象,你必须释放它。

当在@synthesize语句中使用retain setter语义设置时,您要求编译器为您创build一个调用retain在对象上的setter。 没有什么比这更less的了。 而且由于你保留了这个对象(即使它是通过神奇的自动生成的代码),你必须释放它,并释放它的地方是-(void)dealloc

还有一些值得了解 – 如果你有一个合成的属性,将该属性设置为零(当然使用点语法)将释放你的伊娃。