假设我有一个名为SomeClass的类,它有一个字符串属性名:

@interface SomeClass : NSObject
{
    NSString* name;
}

@property (nonatomic, retain) NSString* name;

@end

我知道,名字可以被分配一个NSMutableString在这种情况下,这可能会导致错误的行为。

对于一般的字符串,使用copy属性而不是retain属性总是一个好主意吗? “复制”的属性是否比“保留”的属性效率低?


当前回答

Copy应该用于NSString。如果它是可变的,那么它就会被复制。如果不是,那么它就会被保留。正是你在应用程序中想要的语义(让类型发挥最好的作用)。

其他回答

Copy应该用于NSString。如果它是可变的,那么它就会被复制。如果不是,那么它就会被保留。正是你在应用程序中想要的语义(让类型发挥最好的作用)。

对于类型为符合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。)

通过这个例子,复制和保留可以这样解释:

NSMutableString *someName = [NSMutableString stringWithString:@"Chris"];

Person *p = [[[Person alloc] init] autorelease];
p.name = someName;

[someName setString:@"Debajit"];

如果属性的类型是copy,则,

将为[Person name]字符串创建一个新的副本,该副本将包含someename字符串的内容。现在对someename字符串的任何操作都不会对[Person name]产生影响。

[Person name]和someename字符串将有不同的内存地址。

但是在保留的情况下,

[Person name]将与someename字符串拥有相同的内存地址,只是someename字符串的保留计数将增加1。

因此,someename字符串中的任何更改都将反映在[Person name]字符串中。

如果字符串非常大,那么复制将影响性能,两个大字符串的副本将使用更多的内存。

因为name是一个(不可变的)NSString,复制或保留没有区别,如果你设置另一个NSString为name。换句话说,复制的行为就像retain一样,将引用计数增加1。我认为这是对不可变类的自动优化,因为它们是不可变的,不需要克隆。但是当一个NSMutalbeString mstr被设置为name时,为了正确起见,mstr的内容将被复制。