Let's say I have a class called SomeClass
with a string
property name:
@interface SomeClass : NSObject
{
NSString* name;
}
@property (nonatomic, retain) NSString* name;
@end
I understand that name may be assigned a NSMutableString
in which case this may lead to errant behavior.
- For strings in general, is it always a good idea to use the
copy
attribute instead ofretain
? - Is a "copied" property in any way less efficient than such a "retain-ed" property?
Through this example copy and retain can be explained like:
if the property is of type copy then ,
a new copy will be created for the
[Person name]
string that will hold the contents ofsomeName
string. Now any operation onsomeName
string will have no effect on[Person name]
.[Person name]
andsomeName
strings will have different memory addresses.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.So any change in somename string will be reflected in
[Person name]
string.For attributes whose type is an immutable value class that conforms to the
NSCopying
protocol, you almost always should specifycopy
in your@property
declaration. Specifyingretain
is something you almost never want in such a situation.Here's why you want to do that:
The current value of the
Person.name
property will be different depending on whether the property is declaredretain
orcopy
— it will be@"Debajit"
if the property is markedretain
, but@"Chris"
if the property is markedcopy
.Since in almost all cases you want to prevent mutating 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@synthesize
you should remember to actually usecopy
instead ofretain
in it.)You should use copy all the time to declare NSString property
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)
NSCopying Protocol Reference
Value Objects
Yes - in general always use the copy attribute.
This is because your NSString property can be passed an NSString instance or an NSMutableString instance, and therefore we can not really determine if the value being passed is an immutable or mutable object.
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 instance then 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
NSCopying
protocol, it's possible to implement a class which is "just as efficient" to copy as it is to retain. NSString instances are an example of this.You should always use
copy
when 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 andNSCopying
).There may be performance reasons to
retain
objects, 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.No - use
copy
. If your class is really immutable then it's best practice to implement theNSCopying
protocol to make your class return itself whencopy
is used. If you do this:copy
.copy
annotation makes your own code more maintainable - thecopy
annotation indicates that you really don't need to worry about this object changing state elsewhere.I try to follow this simple rule:
Do I want to hold on to the value of the object at the point in time when I am assigning it to my property? Use copy.
Do I want to hold on to the object and I don't care what its internal values currently 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 person Lisa Miller (strong)? Her name might later change to "Lisa Smith", but she will still be the same person.
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.:
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.com has the following to say:
"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:
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.