e.J*_*mes 65 compiler-construction memory-management properties objective-c
我对Objective-C中的合成属性有一些疑问.完整列表如下,但基本问题是:编译器如何确保正确释放合成属性的ivars,即使我的代码可能包含或不包含dealloc中的release方法?
注意:我决定不将这些问题作为单独的问题发布,因为它们密切相关,并且因为有一些现有的问题涉及到个别问题,而没有真正了解问题的核心.
有些类似的问题:
设置:考虑具有单个属性的类:
@interface Person : NSObject
{
NSString * name;
}
@property (nonatomic, retain) name;
@end
Run Code Online (Sandbox Code Playgroud)
问题#1:最基本的案例:
@implementation Person
@synthesize name;
@end
Run Code Online (Sandbox Code Playgroud)
通过这种设置,我假设name每当一个Person对象被释放时它将自动释放.在我看来,编译器只是插入[name release]到dealloc方法中,就像我自己键入它一样.那是对的吗?
问题2:如果我选择dealloc为这个类编写我自己的方法,并且我省略了一个调用[name release],那会泄漏吗?
@implementation Person
@synthesize name;
- (void)dealloc { [super dealloc]; }
@end
Run Code Online (Sandbox Code Playgroud)
问题3:如果我选择dealloc为这个类编写我自己的方法,并且我包含一个调用[name release],那会导致双重释放,因为@synthesize已经为我处理了它吗?
@implementation Person
@synthesize name;
- (void)dealloc { [name release]; [super dealloc]; }
@end
Run Code Online (Sandbox Code Playgroud)
问题4:如果我选择为这个类编写我自己的属性访问器,但是我不编写自己的dealloc方法,会name被泄露吗?
@implementation Person
@dynamic name;
- (void)setName:(NSString *)newName
{
[newName retain];
[name release];
name = newName;
}
@end
Run Code Online (Sandbox Code Playgroud)
问题5:我有一种感觉,(根据经验),其没有上述情形会导致泄漏或双版本,因为该语言的设计,以避免它们.当然,这提出了"如何?"的问题.编译器是否足够智能以跟踪每个可能的情况?如果我要做以下事情该怎么办(注意这是一个荒谬的例子,只是为了说明我的观点):
void Cleanup(id object) { [object release]; }
@implementation Person
@synthesize name;
- (void)dealloc { Cleanup(name); }
@end
Run Code Online (Sandbox Code Playgroud)
将这种欺骗编译器将添加其他[name release]的dealloc方法?
ken*_*ytm 57
Q1:
号@synthesize不修改-dealloc为您服务.你必须-release对name你自己.
Q2:
是的,它会泄漏.与Q1相同的原因.
Q3:
不,它不会双重释放.与Q1相同的原因.
Q4:
是的,它会泄漏.与Q1相同的原因.
Q5:
不,它不会双重释放.与Q1相同的原因.
您可以通过覆盖来自行检查-retain,-release并-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];
y.x = x;
[y release];
[x release];
[pool drain];
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在Q1,Q2和Q4中,最后-retainCount一个x是1,所以有泄漏,在Q3和Q5中,最后一个-retainCount是0并被-dealloc调用,所以没有泄漏.
Dav*_*ave 17
的dealloc
声明的属性从根本上取代了访问器方法声明; 在合成属性时,编译器仅创建任何缺少的访问器方法.没有与dealloc方法的直接交互 - 不会自动为您释放属性.但是,声明的属性提供了一种交叉检查dealloc方法实现的有用方法:您可以在头文件中查找所有属性声明,并确保释放未标记为assign的对象属性,并标记为assign的对象属性为没有发布.
这基本上回答了你的所有问题.
简单而通用的规则:如果分配,保留或复制对象,则必须释放它.
当您retain在@synthesize语句中使用setter语义设置时,您要求编译器为您构建一个调用retain该对象的setter .没有更多,没有更少.而且由于你保留了那个对象(即使它是通过神奇的自动生成代码),你必须释放它,并在哪里发布它-(void)dealloc.