当前位置:  开发笔记 > 编程语言 > 正文

NSString属性:复制还是保留?

如何解决《NSString属性:复制还是保留?》经验,为你挑选了5个好方法。

比方说,我有一个叫做类SomeClassstring属性名称:

@interface SomeClass : NSObject
{
    NSString* name;
}

@property (nonatomic, retain) NSString* name;

@end

我知道可能会指定名称,NSMutableString在这种情况下,这可能会导致错误的行为.

对于字符串一般来说,使用属性是否总是一个好主意copy而不是retain

"复制"属性是否比这种"保留"属性效率低?

Chris Hanson.. 440

对于类型是符合NSCopying协议的不可变值类的属性,您几乎总是应copy@property声明中指定.指定retain是在这种情况下你几乎不想要的东西.

这就是你想要这样做的原因:

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

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

[someName setString:@"Debajit"];

在的当前值Person.name属性将取决于属性是否被宣布是不同的retaincopy-这将是@"Debajit",如果属性标记retain,但@"Chris"如果该属性被标记copy.

因为在几乎所有情况下,您都希望防止在其背后改变对象的属性,所以应该标记表示它们的属性copy.(如果你自己编写setter而不是使用@synthesize你应该记住实际使用copy而不是使用retain它.)



1> Chris Hanson..:

对于类型是符合NSCopying协议的不可变值类的属性,您几乎总是应copy@property声明中指定.指定retain是在这种情况下你几乎不想要的东西.

这就是你想要这样做的原因:

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

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

[someName setString:@"Debajit"];

在的当前值Person.name属性将取决于属性是否被宣布是不同的retaincopy-这将是@"Debajit",如果属性标记retain,但@"Chris"如果该属性被标记copy.

因为在几乎所有情况下,您都希望防止在其背后改变对象的属性,所以应该标记表示它们的属性copy.(如果你自己编写setter而不是使用@synthesize你应该记住实际使用copy而不是使用retain它.)


你的推理是不正确的.您不应该根据时间/内存确定是复制还是保留,您应该根据所需的语义来确定.这就是我在答案中特别使用"不可变价值等级"一词的原因.这也不是一个类是否具有可变子类,或者本身是否可变的问题.
这个答案可能引起了一些混乱(见http://robnapier.net/blog/implementing-nscopying-439#comment-1312).关于NSString你是完全正确的,但我相信你的观点有点过于笼统.应该复制NSString的原因是它有一个共同的可变子类(NSMutableString).对于没有可变子类的类(特别是您自己编写的类),通常最好保留它们而不是复制,以避免浪费时间和内存.
令人遗憾的是,Obj-C无法按类型强制执行不变性.这与C++缺少传递const一样.我个人工作*好像*字符串总是不可变的.如果我需要使用可变字符串,我将永远不会发出不可变引用,如果我稍后可能会改变它.我认为任何不同的东西都是代码味道.结果 - 在我的代码中(我单独工作)我在所有字符串上使用retain.如果我作为团队的一员工作,我可能会以不同的方式看待事物.
@Nikolai我只是不使用`NSMutableString`,除了作为一个瞬态"字符串构建器"类型(从中我立即采用不可变副本).我希望它们是谨慎的类型 - 但是如果原始字符串不可变,我会允许复制可以自由地执行保留这一事实减轻了我的大部分担忧.
@Phil Nash:我认为对于你单独工作的项目和你与他人分享的项目使用不同的样式是一种代码味道.在每种语言/框架中,都有开发人员同意的共同规则或样式.在私人项目中无视他们似乎是错误的.并且根据你的理由"在我的代码中,我没有返回可变字符串":这可能适用于你自己的字符串,但你永远不会知道从框架中收到的字符串.
@Nikolai - 你是说有框架方法返回不可变字符串但可能会改变它们吗?我知道你的意思是根据项目使用不同风格的气味.我的观点是,我认为整个"不可变的字符串可能是可变的"是一种代码气味,我可以从我自己的项目中消除.

2> Frank Kruege..:

复制应该用于NSString.如果它是Mutable,那么它会被复制.如果不是,那么它就会被保留下来.确切地说,你在应用程序中想要的语义(让类型做到最好).


提及`NSString`属性声明为`copy`的+1,无论如何都会得到`retain`(当然,如果它是不可变的).我能想到的另一个例子是`NSNumber`.

3> TJez..:

对于一般的字符串,使用copy属性而不是retain是否总是一个好主意?

是 - 通常始终使用copy属性.

这是因为您的NSString属性可以传递给NSString实例NSMutableString实例,因此我们无法确定传递的值是不可变对象还是可变对象.

"复制"属性是否比这种"保留"属性效率低?

如果您的属性正在传递NSString实例,答案是" " - 复制的效率不低于保留.
(效率并不低,因为NSString非常智能,无法实际执行副本.)

如果您的属性传递给NSMutableString实例,那么答案是" " - 复制效率低于保留.
(效率较低,因为必须进行实际的内存分配和复制,但这可能是理想的事情.)

一般来说,"复制"属性可能效率较低 - 但是通过使用NSCopying协议,可以实现一个"同样有效"的类来保留它.NSString实例就是一个例子.

通常(不仅仅是NSString),什么时候应该使用"copy"而不是"retain"?

copy当您不希望属性的内部状态在没有警告的情况下更改时,应始终使用.即使对于不可变对象 - 正确编写的不可变对象也会有效地处理复制(请参阅下一节有关不变性的内容NSCopying).

retain对象可能存在性能原因,但它带来了维护开销 - 您必须管理内部状态在代码外部更改的可能性.正如他们所说 - 优化最后.

但是,我写的课程是不可改变的 - 我不能只是"保留"它吗?

不 - 使用copy.如果你的类真的是不可变的,那么最好的做法是实现NSCopying协议,让你的类在copy使用时自行返回.如果你这样做:

您班级的其他用户在使用时将获得性能优势copy.

copy注解让自己的代码更易于维护-的copy注释表明你真的不需要担心这个对象改变别处状态.



4> Johannes Fah..:

我试着遵循这个简单的规则:

我是否希望在将其分配给我的财产保留对象的价值?使用副本.

我是否想要坚持这个对象,我不关心它的内部价值目前是什么或将来会是什么?使用(保留).

举例说明:我是否想要坚持"Lisa Miller" 这个名字(副本)或者我想坚持Lisa Miller(强者)这个?她的名字可能会改为"丽莎史密斯",但她仍然是同一个人.



5> 小智..:

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

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

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

[someName setString:@"Debajit"];

如果属性是复制类型,那么,

将为[Person name]将保存someName字符串内容的字符串创建一个新副本.现在对someName字符串的任何操作都不会起作用[Person name].

[Person name]someName字符串将具有不同的内存地址.

但是如果保留,

两者都[Person name]将保存与somename字符串相同的内存地址,只是somename字符串的保留计数将增加1.

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

推荐阅读
跟我搞对象吧
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有