几个想法:
最佳实践是根本不编写设置器,以利用自动合成的访问器方法)。自己编写只是一个搞乱内存管理或引入错误的机会。在编写自定义设置器之前,您应该迫切需要自定义设置器。
实例变量名称的新兴约定是使用前导下划线开头的属性名称(例如,对于名为 的属性name
,ivar 是_name
)。如果您省略该@synthesize
语句,最新版本的 Xcode 中包含的编译器将自动为您执行此操作。
如果您没有说明您的属性具有哪些内存限定符,那么设置器应该是什么的问题是没有意义的。我将假设您将您的财产定义为retain
.
将属性更改为 aNSMutableString
会更改您的属性的行为,除非您出于某种原因确实需要可变字符串,否则我不建议这样做。
name
如果有人将属性设置为 ,您的第一个示例什么也不做nil
。但是如果有人想将它设置为nil
,你仍然应该(a)释放旧name
值;(b) 将您的 ivar 设置为nil
. (顺便说一句,我下面的代码利用了这样一个事实,即向对象发送消息什么都不做,所以在这种情况下nil
,我不需要检查它是否存在。)nil
所以,我假设你有一个定义如下的属性:
@property (nonatomic, retain) NSString *name;
以及一条被省略或看起来像这样的合成线:
@synthesize name = _name;
然后,我认为二传手看起来像:
-(void) setName:(NSString *)name
{
// if you want to program defensively, you might want the following assert statement:
//
// NSAssert(name == nil || [name isKindOfClass:[NSString class]], @"%s: name is not string", __FUNCTION__);
if (name != _name)
{
[_name release];
_name = name;
[_name retain];
}
}
顺便说一句,我假设您的init
方法正确初始化_name
并dealloc
释放它。
- (id)init
{
self = [super init];
if (self) {
_name = nil;
}
return self;
}
- (void)dealloc
{
[_name release];
[super dealloc];
}
正如 bblum 指出的那样,谨慎使用copy
您的NSString
属性:
@property (nonatomic, copy) NSString *name;
然后,我认为二传手看起来像:
-(void) setName:(NSString *)name
{
// if you want to program defensively, you might want the following assert statement:
//
// NSAssert(name == nil || [name isKindOfClass:[NSString class]], @"%s: name is not string", __FUNCTION__);
if (name != _name)
{
[_name release];
_name = [name copy];
}
}
但实际上,除非绝对需要,否则您根本不应该编写 setter。
最后,您的代码有一条关于发现内存管理令人困惑的注释。虽然您肯定需要了解它,但我会提出两个最终建议:
考虑使用自动引用计数(ARC)。虽然这并不能排除理解内存管理如何工作的需要(请参阅高级内存管理编程指南),但它确实使编写正确处理内存管理的代码变得更加容易。如果您编写手动引用计数 (MRC) 代码,则很容易犯简单的内存管理错误,否则 ARC 会为您处理这些错误。
特别是如果您要使用 MRC,请使用 Xcode 的静态分析器(“产品”菜单上的“分析”或按shift+ command+ B)。这有助于发现困扰 MRC 代码的许多常规内存管理问题。Instruments 用户指南的查找内存泄漏部分还说明了如何在调试代码时发现泄漏,但静态分析器通常可以通过检查代码来识别问题。