objective-c NSString 属性:复制还是保留?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/387959/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
NSString property: copy or retain?
提问by PlagueHammer
Let's say I have a class called SomeClasswith a stringproperty name:
假设我有一个SomeClass使用string属性名称调用的类:
@interface SomeClass : NSObject
{
NSString* name;
}
@property (nonatomic, retain) NSString* name;
@end
I understand that name may be assigned a NSMutableStringin which case this may lead to errant behavior.
我知道该名称可能会被分配一个,NSMutableString在这种情况下这可能会导致错误的行为。
- For strings in general, is it alwaysa good idea to use the
copyattribute instead ofretain? - Is a "copied" property in any way less efficient than such a "retain-ed" property?
- 对于一般的字符串,是它总是用一个好主意
copy属性,而不是retain? - “复制”的财产是否比这种“保留”的财产效率低?
回答by Chris Hanson
For attributes whose type is an immutable value class that conforms to the NSCopyingprotocol, you almost always should specify copyin your @propertydeclaration. Specifying retainis something you almost never want in such a situation.
对于类型为符合NSCopying协议的不可变值类的属性,您几乎总是应该copy在@property声明中指定。retain在这种情况下,指定是您几乎从不想要的。
Here's why you want to do that:
这就是您想要这样做的原因:
NSMutableString *someName = [NSMutableString stringWithString:@"Chris"];
Person *p = [[[Person alloc] init] autorelease];
p.name = someName;
[someName setString:@"Debajit"];
The current value of the Person.nameproperty will be different depending on whether the property is declared retainor copy— it will be @"Debajit"if the property is marked retain, but @"Chris"if the property is marked copy.
Person.name属性的当前值将根据属性是否被声明retain或copy-@"Debajit"如果属性被标记retain,但@"Chris"如果属性被标记而不同copy。
Since in almost all cases you want to preventmutating an object's attributes behind its back, you should mark the properties representing them copy. (And if you write the setter yourself instead of using @synthesizeyou should remember to actually use copyinstead of retainin it.)
由于几乎在所有情况下您都希望防止在背后改变对象的属性,因此您应该标记表示它们的属性copy。(如果您自己编写 setter 而不是使用,@synthesize您应该记住实际使用copy而不是retain在其中使用。)
回答by Frank Krueger
Copyshould be used for NSString. If it's Mutable, then it gets copied. If it's not, then it just gets retained. Exactly the semantics that you want in an app (let the type do what's best).
副本应该用于 NSString。如果它是可变的,那么它就会被复制。如果不是,那么它只会被保留。正是您在应用程序中想要的语义(让类型做最好的事情)。
回答by TJez
For strings in general, is it always a good idea to use the copy attribute instead of retain?
对于一般的字符串,使用复制属性而不是保留总是一个好主意吗?
Yes - in general always use the copy attribute.
是的 - 通常总是使用 copy 属性。
This is because your NSString propertycan be passed an NSString instanceor an NSMutableString instance, and therefore we can not really determine if the value being passed is an immutable or mutable object.
这是因为您的NSString 属性可以传递NSString 实例或NSMutableString 实例,因此我们无法真正确定传递的值是不可变对象还是可变对象。
Is a "copied" property in any way less efficient than such a "retain-ed" property?
“复制”的财产是否比这种“保留”的财产效率低?
If your property is being passed an NSString instance, the answer is "No" - copying is not less efficient than retain.
(It's not less efficient because the NSString is smart enough to not actually perform a copy.)If your property is passed an NSMutableString instancethen the answer is "Yes" - copying is less efficient than retain.
(It's less efficient because an actual memory allocation and copy must occur, but this is probably a desirable thing.)Generally speaking a "copied" property has the potential to be less efficient - however through the use of the
NSCopyingprotocol, it's possible to implement a class which is "just as efficient" to copy as it is to retain. NSString instancesare an example of this.
如果您的属性正在传递一个NSString 实例,答案是“否”——复制并不比保留效率低。
(它的效率并不低,因为 NSString 足够智能,实际上不会执行复制。)如果您的属性被传递了一个NSMutableString 实例,那么答案是“是”——复制的效率低于保留。
(它的效率较低,因为必须进行实际的内存分配和复制,但这可能是可取的。)一般来说,“复制”的属性可能会降低效率——但是通过使用
NSCopying协议,可以实现一个复制和保留“同样有效”的类。NSString 实例就是一个例子。
Generally (not just for NSString), when should I use "copy" instead of "retain"?
通常(不仅仅是 NSString),我什么时候应该使用“复制”而不是“保留”?
You should always use copywhen you don't want the internal state of the property changing without warning. Even for immutable objects - properly written immutable objects will handle copy efficiently (see next section regarding immutability and NSCopying).
copy当您不想在没有警告的情况下更改属性的内部状态时,您应该始终使用。即使对于不可变对象 - 正确编写的不可变对象将有效地处理复制(请参阅下一节关于不变性和NSCopying)。
There may be performance reasons to retainobjects, but it comes with a maintenance overhead - you must manage the possibility of the internal state changing outside your code. As they say - optimize last.
retain对象可能有性能方面的原因,但它带来了维护开销 - 您必须管理代码外部更改内部状态的可能性。正如他们所说 - 最后优化。
But, I wrote my class to be immutable - can't I just "retain" it?
但是,我把我的类写成不可变的——我不能“保留”它吗?
No - use copy. If your class is really immutable then it's best practice to implement the NSCopyingprotocol to make your class return itself when copyis used. If you do this:
不可用copy。如果您的类确实是不可变的,那么最好实现NSCopying协议以使您的类在copy使用时返回自身。如果你这样做:
- Other users of your class will gain the performance benefits when they use
copy. - The
copyannotation makes your own code more maintainable - thecopyannotation indicates that you really don't need to worry about this object changing state elsewhere.
- 您班级的其他用户在使用
copy. - 该
copy注解让自己的代码更易于维护-的copy注释表明你真的不需要担心这个对象改变别处状态。
回答by Johannes Fahrenkrug
I try to follow this simple rule:
我尝试遵循这个简单的规则:
Do I want to hold on to the valueof the object at the point in time when I am assigning itto my property? Use copy.
Do I want to hold on to the objectand I don't care what its internal valuescurrently are or will be in the future? Use strong(retain).
当我将其分配给我的财产时,我是否想保留该对象的价值?使用副本。
我是否想抓住这个对象,而不关心它目前或将来的内部价值是什么?使用强(保留)。
To illustrate: Do I want to hold on to the name"Lisa Miller" (copy) or to I want to hold on to the personLisa Miller (strong)? Her name might later change to "Lisa Smith", but she will still be the same person.
举例说明:我是想保留“丽莎米勒”这个名字(副本)还是我想保留丽莎米勒这个人(强)?她的名字以后可能会更改为“Lisa Smith”,但她仍然是同一个人。
回答by Divya Arora
Through this example copy and retain can be explained like:
通过这个例子复制和保留可以解释如下:
NSMutableString *someName = [NSMutableString stringWithString:@"Chris"];
Person *p = [[[Person alloc] init] autorelease];
p.name = someName;
[someName setString:@"Debajit"];
if the property is of type copy then ,
如果该属性的类型为 copy ,则
a new copy will be created for the [Person name]string that will hold the contents of someNamestring. Now any operation on someNamestring will have no effect on [Person name].
[Person name]将为保存someName字符串内容的字符串创建一个新副本。现在对someName字符串的任何操作都不会影响[Person name].
[Person name]and someNamestrings will have different memory addresses.
[Person name]和someName字符串将具有不同的内存地址。
But in case of retain,
但在保留的情况下,
both the [Person name]will hold the same memory address as of somename string, just the retain count of somename string will be incremented by 1.
两者都[Person name]将持有与 somename 字符串相同的内存地址,只是 somename 字符串的保留计数将增加 1。
So any change in somename string will be reflected in [Person name]string.
因此,somename 字符串中的任何更改都将反映在[Person name]字符串中。
回答by Clarkeye
Surely putting 'copy' on a property declaration flies in the face of using an object-oriented environment where objects on the heap are passed by reference - one of the benefits you get here is that, when changing an object, all references to that object see the latest changes. A lot of languages supply 'ref' or similar keywords to allow value types (i.e. structures on the stack) to benefit from the same behaviour. Personally, I'd use copy sparingly, and if I felt that a property value should be protected from changes made to the object it was assigned from, I could call that object's copy method during the assignment, e.g.:
面对使用面向对象的环境(其中堆上的对象通过引用传递),将“复制”放在属性声明上肯定会失败 - 您在这里获得的好处之一是,在更改对象时,所有对该对象的引用查看最新变化。许多语言提供“ref”或类似的关键字以允许值类型(即堆栈上的结构)从相同的行为中受益。就我个人而言,我会谨慎使用 copy,如果我觉得应该保护属性值免受对其分配的对象所做的更改,我可以在分配期间调用该对象的 copy 方法,例如:
p.name = [someName copy];
Of course, when designing the object that contains that property, only you will know whether the design benefits from a pattern where assignments take copies - Cocoawithlove.comhas the following to say:
当然,在设计包含该属性的对象时,只有您会知道设计是否受益于赋值复制的模式 - Cocoawithlove.com有以下说法:
"You should use a copy accessor when the setter parameter may be mutable but you can't have the internal state of a property changing without warning" - so the judgement as to whether you can stand the value to change unexpectedly is all your own. Imagine this scenario:
“当 setter 参数可能是可变的但你不能在没有警告的情况下改变属性的内部状态时,你应该使用复制访问器” - 所以你是否能忍受值意外改变的判断完全是你自己的。想象一下这个场景:
//person object has details of an individual you're assigning to a contact list.
Contact *contact = [[[Contact alloc] init] autorelease];
contact.name = person.name;
//person changes name
[[person name] setString:@"new name"];
//now both person.name and contact.name are in sync.
In this case, without using copy, our contact object takes the new value automatically; if we did use it, though, we'd have to manually make sure that changes were detected and synced. In this case, retain semantics might be desirable; in another, copy might be more appropriate.
在这种情况下,不使用复制,我们的联系人对象会自动采用新值;但是,如果我们确实使用了它,我们就必须手动确保检测到并同步更改。在这种情况下,保留语义可能是可取的;另一方面,复制可能更合适。
回答by len
@interface TTItem : NSObject
@property (nonatomic, copy) NSString *name;
@end
{
TTItem *item = [[TTItem alloc] init];
NSString *test1 = [NSString stringWithFormat:@"%d / %@", 1, @"Go go go"];
item.name = test1;
NSLog(@"-item.name: point = %p, content = %@; test1 = %p", item.name, item.name, test1);
test1 = [NSString stringWithFormat:@"%d / %@", 2, @"Back back back"];
NSLog(@"+item.name: point = %p, content = %@, test1 = %p", item.name, item.name, test1);
}
Log:
-item.name: point = 0x9a805a0, content = 1 / Go go go; test1 = 0x9a805a0
+item.name: point = 0x9a805a0, content = 1 / Go go go, test1 = 0x9a84660
回答by onmyway133
You should use copyall the time to declare NSString property
你应该一直使用copy来声明 NSString 属性
@property (nonatomic, copy) NSString* name;
You should read these for more information on whether it returns immutable string (in case mutable string was passed) or returns a retained string (in case immutable string was passed)
您应该阅读这些以获取有关它是否返回不可变字符串(如果传递了可变字符串)或返回保留字符串(如果传递了不可变字符串)的更多信息
Implement NSCopying by retaining the original instead of creating a new copy when the class and its contents are immutable
当类及其内容不可变时,通过保留原始副本而不是创建新副本来实现 NSCopying
So, for our immutable version, we can just do this:
因此,对于我们的不可变版本,我们可以这样做:
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
回答by Hyman
If the string is very large then copy will affect performance and two copies of the large string will use more memory.
如果字符串非常大,则复制会影响性能,并且大字符串的两个副本将使用更多内存。
回答by GBY
Since name is a (immutable) NSString, copy or retain makes no difference if you set another NSStringto name. In another word, copy behaves just like retain, increasing the reference count by one. I think that is an automatic optimization for immutable classes, since they are immutable and of no need to be cloned. But when a NSMutalbeStringmstris set to name, the content of mstrwill be copied for the sake of correctness.
由于 name 是 (immutable) NSString,如果您将另一个设置NSString为 name ,则复制或保留没有区别。换句话说,复制的行为就像保留一样,将引用计数增加一。我认为这是对不可变类的自动优化,因为它们是不可变的,不需要克隆。但是当 aNSMutalbeStringmstr设置为 name 时,mstr为了正确起见,将复制其中的内容。

