NSString属性:复制或保留?
假设我有一个名为SomeClass
的类,它具有一个string
属性名称:
@interface SomeClass : NSObject
{
NSString* name;
}
@property (nonatomic, retain) NSString* name;
@end
我知道这个名字可能会被分配一个NSMutableString
在这种情况下,这可能会导致错误的行为。
copy
属性而不是retain
是个好主意吗? 对于类型为符合NSCopying
协议的不可变值类的属性,几乎总是应该在@property
声明中指定copy
。 指定retain
是你在这种情况下几乎不需要的东西。
这就是为什么你想这样做:
NSMutableString *someName = [NSMutableString stringWithString:@"Chris"];
Person *p = [[[Person alloc] init] autorelease];
p.name = someName;
[someName setString:@"Debajit"];
Person.name
属性的当前值将根据属性是否声明为retain
或copy
而有所不同 - 如果属性标记为retain
,则为@"Debajit"
如果属性标记为copy
则为@"Chris"
。
由于在几乎所有情况下,您都希望防止对象背后的对象属性发生变化,因此应该将代表它们的属性标记为copy
。 (如果你自己编写setter而不是使用@synthesize
你应该记得实际使用copy
而不是retain
。)
复制应该用于NSString。 如果它是可变的,那么它会被复制。 如果不是,那么它会被保留下来。 准确地说你想在应用中使用的语义(让类型做最好的)。
对于一般的字符串,使用copy属性而不是retain是个好主意吗?
是的 - 一般总是使用复制属性。
这是因为你的NSString属性可以传递一个NSString实例或一个NSMutableString实例 ,因此我们不能真正确定被传递的值是不可变的还是可变的对象。
是否“复制”的财产比这样的“保留财产”效率低?
如果您的属性正在传递NSString实例 ,则答案为“ 否 ” - 复制的效率并不低于保留。
(它的效率并不低,因为NSString足够聪明,不会真正执行副本。)
如果你的属性传递了一个NSMutableString实例,那么答案是“ 是 ” - 复制效率低于保留。
(效率不高,因为实际的内存分配和复制必须发生,但这可能是一个理想的事情。)
一般来说,“复制”属性可能效率较低 - 但通过使用NSCopying
协议,可以实现一个“同样高效”的类来复制和保留。 NSString实例就是这样的一个例子。
一般来说(不只是对于NSString),什么时候应该使用“复制”而不是“保留”?
如果您不希望在没有警告的情况下更改内部状态,则应始终使用copy
。 即使对于不可变的对象 - 正确编写的不可变对象将有效地处理拷贝(参见下一节关于不变性和NSCopying
)。
retain
对象可能有性能方面的原因,但它带来了维护开销 - 您必须管理内部状态在代码之外更改的可能性。 正如他们所说 - 最后优化。
但是,我写我的课是不变的 - 我不能“保留”它吗?
不使用copy
。 如果你的类真的是不可变的,那么最好的做法是实现NSCopying
协议,使你的类在使用copy
时自动返回。 如果你这样做:
copy
时将获得性能优势。 copy
注释使您自己的代码更易于维护 - copy
注释表明您确实无需担心其他位置的此对象更改状态。