NSString property: copy or retain? - objective-c

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 of retain?
Is a "copied" property in any way less efficient than such a "retain-ed" property?

For attributes whose type is an immutable value class that conforms to the NSCopying protocol, you almost always should specify copy in your #property declaration. Specifying retain is something you almost never want in such a situation.
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.name property will be different depending on whether the property is declared retain or copy — it will be #"Debajit" if the property is marked retain, but #"Chris" if the property is marked copy.
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 use copy instead of retain in it.)

Copy should 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).

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.
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.
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 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.
Generally (not just for NSString), when should I use "copy" instead of "retain"?
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 and NSCopying).
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.
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 NSCopying protocol to make your class return itself when copy is used. If you do this:
Other users of your class will gain the performance benefits when they use copy.
The copy annotation makes your own code more maintainable - the copy 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.

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 ,
a new copy will be created for the [Person name] string that will hold the contents of someName string. Now any operation on someName string will have no effect on [Person name].
[Person name] and someName 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.

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.:
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.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:
//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.

#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

You should use copy all the time to declare NSString property
#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)
NSCopying Protocol Reference
Implement NSCopying by retaining the original instead of creating a
new copy when the class and its contents are immutable
Value Objects
So, for our immutable version, we can just do this:
- (id)copyWithZone:(NSZone *)zone
{
return self;
}

Since name is a (immutable) NSString, copy or retain makes no difference if you set another NSString to 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 NSMutalbeString mstr is set to name, the content of mstr will be copied for the sake of correctness.

If the string is very large then copy will affect performance and two copies of the large string will use more memory.

Related

Is there any real point to the (copy) attribute in a property?

I had assumed that the purpose of the copy attribute was so that I could just assign one property to another (say) and have the underlying getter/setter methods handle everything properly. But having reviewed a number of articles (including some on stackoverflow) it's not clear to me that there's any real benefit over simply using the appropriate methods to copy stuff explicitly. For a start, I discovered that assigning a mutable string to another mutable string still leaves you with a non-mutable string, so what good is that?
Does this work properly for other classes? In other words, in general, if I have
#property (copy) Foo* f1;
#property (copy) Foo* f2;
....
#property (copy) Foo* fn;
can I generally write
f1 = f2
f3 = f2
and get proper copies, i.e. completely independent objects?
(copy) will call the copy method on the item being set, so it will depend on the object. Let's see an example with NSString and see if that helps?
Two classes ObjectWithCopy
#interface ObjectWithCopy : NSObject
#property (copy) NSString *aString;
#end
and ObjectWithoutCopy
#interface ObjectWithoutCopy : NSObject
#property (strong) NSString *aString;
#end
Pretty easy so far, and we all know NSString is immutable, so what will "copy" do? Well remember NSMutableString is a subclass of NSString. So we could pass that in to the setter instead. What happens when we do this?
NSMutableString *aMutableString = [[NSMutableString alloc] initWithString:#"Hello World"];
ObjectWithCopy *objectWithCopy = [[ObjectWithCopy alloc] init];
objectWithCopy.aString = aMutableString;
NSLog(#"ObjectWithCopy.aString = %#", objectWithCopy.aString);
//Now we change aMutableString
[aMutableString appendString:#" and every other world"];
NSLog(#"ObjectWithCopy.aString after aMutableString was modified = %#", objectWithCopy.aString);
NSLog(#"Now what happens without copy?");
// Reset aMutableString
aMutableString = [[NSMutableString alloc] initWithString:#"Hello World"];
ObjectWithoutCopy *objectWithoutCopy = [[ObjectWithoutCopy alloc] init];
objectWithoutCopy.aString = aMutableString;
NSLog(#"ObjectWithoutCopy.aString = %#", objectWithoutCopy.aString);
//Now we change aMutableString and see what objectWithoutCopy.aString is?
[aMutableString appendString:#" and every other world"];
NSLog(#"ObjectWithoutCopy.aString after aMutableString was modified = %#", objectWithoutCopy.aString);
The output?
2014-02-02 10:40:04.247 TableViewCellWithAutoLayout[95954:a0b] ObjectWithCopy.aString = Hello World
2014-02-02 10:40:04.248 TableViewCellWithAutoLayout[95954:a0b] ObjectWithCopy.aString after aMutableString was modified = Hello World
2014-02-02 10:40:04.248 TableViewCellWithAutoLayout[95954:a0b] Now what happens without copy?
2014-02-02 10:40:04.248 TableViewCellWithAutoLayout[95954:a0b] ObjectWithoutCopy.aString = Hello World
2014-02-02 10:40:04.249 TableViewCellWithAutoLayout[95954:a0b] ObjectWithoutCopy.aString after aMutableString was modified = Hello World and every other world
Whoa - our immutable string was changed on ObjectWithoutCopy!?!? That's because it really was a NSMutableString after all and without copy we are simply pointing to whatever was passed in. So any changes that occurred with that passed in object will be seen in both the class and the function variable. That is why it's so often suggested that when you have an NSString property you use (copy), you don't expect an NSString to change.
Copy makes the assign statement this _aString = [passedInString copy];. As some have pointed out can do anything so long as it conforms to the NSCopying protocol, but should create an independent copy of the object to make sure change the outside world makes doesn't affect your class. So someone could create a subclass of NSString (which you probably should never do) that overrides copy to do nothing and you could still see your NSString change out from under you, but in general it's a pretty safe bet that NSCopying was done correctly. At least that's the best you can really do.
Edit 1:
As #David mentions in his comment (and is maybe his real question?), [aMutableString copy] actually returns a object of type NSString. I completely agree this is confusing. If I was making NSMutableString I would have copy return a NSMutableString. Actually I think the real WTF here is that Apple has created a mutable subclass of a non-mutable class. In C#/Java, you don't have a mutable string, instead you use another class called StringBuilder.
So if this is so confusing, why do so many people use copy on NSString properties? Because it most likely does what you actually want it to. If your class has an NSString property, you picked that because you don't want to worry about the string changing out from under you. To do that you really want a copy of the string passed in. And if it's a NSMutableString you probably want an NSString copy because you don't want to give that mutable string out and have it changed out from under you. If copy on a NSMutableString returned an NSMutableString I don't think people would use the copy attribute, but create a custom setter that set _aString = [[NSString alloc] initWithString: inputString]. This is probably clearer, and if you think it is that it is maybe what you should do. But at this point it's convention to use copy on NSString properties, so I'll probably continue to use it. You may or may not agree with it, but your question is why do people use copy then this is why I do personally.
Edit 2:
#David asks why doesn't copy work this way? "If I copy a string then I want a subsequent call to be able to change it." I think if you really want the side effects you probably should be declaring an NSMutableString without the copy modifier (you probably should never use copy and NSMutableString, but create your own setter).
I really can't think of a reason in my nearly 15 years of programming why I would not want the person setting the string's side effect but I would want any old person who get's the string's side effect. That's really weird.
Further I can't for the life of me think of why I would want that situation but advertise it as an NSString instead. I mean why? Why would want for your immutable property to be sometimes mutable, but only when the setter (which you don't control) tells you too but you don't want the side effects from from object that was set with. AND you don't tell any one about it and they have to just figure it out? My head hurts.
My guess is this is why Apple did what it did. But it's only a guess.
Further, if you can get away with an immutable data type you should. It reduces all sorts of complexity especially with multithreading.
Of course Objective-C (and most OOP languages) let you do all of this if you really really want to. That's up to you programmer and your team. You can also test the accelerometer by bashing your phone against your skull. I don't think Apple recommends either approach though.
Yes, you get completely independent objects. What else would the copy attribute do?
I think that the copy specifier creates a new instance of an object if it is necessary. For example if the object is mutable (object passed to the setter of course). If not it usually just retains it.
Consider that copy means that the instance is logically copied. The way it is implemented (memory copied or just extra retain) does not matter that much actually.
The copy specifier just means that the -copy method of the object in question will be called during assignment (see: the NSCopying protocol). This method's purpose is usually to return a "completely independent object" so that's usually what you'll get. There are exceptions though.
For instance, if your object is an immutable value (NSString being the canonical example), then there's no reason to -copy it to get an "independent object". So in that case, as an optimization, -copy only results in a retain, not a new object.
Of course, any custom class or subclass can override -copy or -copyWithZone: to do any number of unpredictable, destructive things. But the convention is to return, as you say, an "independent object" — or self in contexts where "independent" doesn't mean anything.

clarification about #property attribute

In the following example, does stringWithString:(NSString *) copy the memory address/location of theName to name or it actually copies the data from theName to name?
#interface AddressCard:NSObject
-(void)setName:(NSString *)theName;
#end
#implementation AddressCard
NSString *name;
-(void)setName:(NSString *)theName
{
if(name!=theName)
name = [NSString stringWithString:theName];
}
#end
If I change the code to following, what does copy do differently?
#interface AddressCard:NSObject
#property (copy, nonatomic) NSString *name;
#end
#implementation AddressCard
#synthesize name;
#end
In general, does copy (#property attribute) copy the address of the data or copies the data from one variable to another? If it is latter case, are we not consuming a lot of memory when the variable represents large data?
Thank you for your time and response!
+[NSString stringWithString:] will effectively 'copy' the string.
In general, does copy (#property attribute) copy the address of the data or copies the data from one variable to another?
It performs whatever the object considers is a copy. It may return a new object, or it may return itself. For example, +[NSString stringWithString:]could just return the parameter retained and autoreleased if the parameter is already immutable. If the parameter is mutable, then it will return a new instance, so you are guaranteed to have an immutable instance.
If it is latter case, are we not consuming a lot of memory when the variable represents large data?
Aha - but that's the trick! Yes, you could end up making many new allocations with copy, but the trick is often that copies of reference counted objects are truly very shallow in most cases when you favor immutable types and using copy. Many collections types can simply return themselves if they are already immutable, or their ivars may do so, so it's actually a really good idea to ensure you are not passing around mutable objects -- so creating an immutable copy early really allows this optimization to propagate, and saves you a ton of allocations (but not always -- there are a number of corner cases for all these variants).
Note: Not all classes distinguish immutability from mutability, so a copy does not always return an immutable object.
stringWithString will create a copy if it's mutable. But be aware since it's not alloc, init, copy method it's autoreleased. The copy you are now holding will go poof at some point right after that set method exits. If you did initWithString instead, it would create another string as well but retain it.
The copy attribute means the property will be assigned the object returned after sending the copy message to the object that was passed in. That means it's up to that object type to determine how it handles a copy. For your specific string example, (copy) will create a copy of the string back to the caller - a copy that's retained. It's up to the caller to release the retained object. According to the memory guidelines, copy will retain the object.

Setting WEAK to a non #property variable

Will need someone with knowledge of ARC to help me.
Basically, I have declared some variables as such in my class
#interface Class{
NSString* one;
NSString* two;
}
#property(nonatomic,weak) NSString* one;
As you can see, I can set the weak identifier to NSString* one. However, I do not need a getter/setter/synthesizer for NSString* two as it is just a common variable. How can I set a weak label to it so the memory is deallocated? Or is automatically set?
You can do it like this:
__weak NSString *two;
But you probably do not want to do it in this case.
Declaring an instance variable __weak means that the reference to the target object (a string in your case) will exist only as long as some other object holds a reference. When the last object holding a strong reference releases the string, your variable two will get nil-ed out automatically. This is very useful when objects hold references to each other, such as in parent-child hierarchies. Since your NSString *two could not possibly hold a reference to your object, using the __weak reference for it is highly questionable.
You can do this without worrying:
NSString* two = [[NSString alloc] init];
When your instance of the class Class is release for some reason, since is the only one (in theory) referencing two, it will be deallocated.
My advice (and I think Apple's although I could be wrong) would be to get into the habit of always using properties for your iVars, then this problem goes away.

Assign or retain in cocos2d and objective C

Here's my current situation:
I have a NSMutableArray named dictKeyArray which I assign a property with #property(nonatomic,retain)NSMutableArray *dictKeyArray
I synthesize my mutable array in the implementation file.
Later, I have a dictionary name storeDict. I assign all the keys of the dictionary to the dictKeyArray like so:
dictKeyArray = [[storeDict allKeys] mutableCopy];
Now I use this dictionary later in my implementation file. However, when it comes to releasing it, I release it once in my dealloc method. When checking with instruments, a leak shows up! Why is dictKeyArray leaking? Should I be using assign instead of retain?
I'm still not clear on what the difference is exactly...
thank you!
You have to send it an
[[[storeDict allKeys] mutableCopy] autorelease];
Just to make this clear: mutableCopy does the same as alloc meaning you are claiming ownership of the object in question. You have to decrease the retainCount by one.
By the way: You should use the accessor you wrote for it. You are just assigning it to your iVar at the moment. If you want to make your accessors work, you will have to use something like
object.dictKeyArray = ...;
in general. Or here (as mentioned by dreamlax)
self.dictKeyArray = ...;
because you are referring to an object of this specific class the code is in.
Only this way you are ensuring your object is properly retained by your accessor. Otherwise writing the accessor code doesn't make sense at all because it never gets called.
Please note: As Josh said in the comments, your code should be valid (at least from my point of view). What I suggested is a solution that is not as error-prone as yours because you adhere to the rules (could save you from headache in the near future).
You should be using self.dictKeyArray = .... Without the self. you are accessing the instance variable directly, bypassing any memory management benefits of properties, but, remember that you own the result of mutableCopy, and assigning to a property that also takes ownership will result in double-ownership, so use:
self.dictKeyArray = [[[storeDict allKeys] mutableCopy] autorelease];

Object allocate and init in Objective C

What is the difference between the following 2 ways to allocate and init an object?
AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];
and
self.aController= [[AController alloc] init];
Most of the apple example use the first method. Why would you allocate, init and object and then release immediately?
Every object has a reference count. When it goes to 0, the object is deallocated.
Assuming the property was declared as #property (retain):
Your first example, line by line:
The object is created by alloc, it has a reference count of 1.
The object is handed over to self's setAController: method, which sends it a retain message (because the method doesn't know where the object is coming from), incrementing its reference count to 2.
The calling code no longer needs the object itself, so it calls release, decrementing the reference count to 1.
Your second example basically does steps 1 and 2 but not 3, so at the end the object's reference count is 2.
The rule is that if you create an object, you are responsible for releasing it when you're done with it. In your example, the code is done with tempAController after it sets the property. It is the setter method's responsibility to call retain if it needs that object to stick around.
It's important to remember that self.property = foo; in Objective-C is really just shorthand for [self setProperty:foo]; and that the setProperty: method is going to be retaining or copying objects as needed.
If the property was declared #property (copy), then the object would have been copied instead of retained. In the first example, the original object would be released right away; in the second example, the original object's reference count would be 1 even though it should be 0. So you would still want to write your code the same way.
If the property was declared #property (assign), then self isn't claiming ownership of the object, and somebody else needs to retain it. In this case, the first example would be incorrect. These sorts of properties are rare, usually only used for object delegates.
As others have noted, the two code snippets you show are not equivalent (for memory management reasons).
As to why the former is chosen over the latter:
The correct formulation of the latter would be
self.aController= [[[AController alloc] init] autorelease];
Compared with the former, this adds additional overhead through use of the autorelease pool, and in some circumstances will lead to the lifetime of the object being unnecessarily extended (until the autorelease pool is released) which will increase your application's memory footprint.
The other "possible" implementation (depending on where the example is from) is simply:
aController = [[AController alloc] init];
However, setting an instance variable directly is strongly discouraged anywhere other than in an init or dealloc method. Elsewhere you should always use accessor methods.
This brings us then to the implementation shown in sample code:
AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];
This follows best practice since:
It avoids autorelease;
It makes the memory management semantics immediately clear;
It uses an accessor method to set the instance variable.
Note also that your desire to cut the code down to one line is why many people use Autorelease:
self.aController = [[[AController alloc] init] autorelease];
Though in theory on the iPhone autorelease is somehow more expensive (never heard a clear explanation why) and thus you may want to explicitly release right after you assign the object elsewhere.
If you're using Xcode, it can help you detect such code with the static analyzer.
Just hit Build >> Build and Analyze
This will show you a very helpful message at such pieces of code.
One other thing to note is that your example depends on the #property definition of aController also.
If it were defined as #property (readwrite, retain) id aController; then your example works, while if it is defined as #property (readwrite, assign) id aController; then the extra call to release would cause your object to be deallocated.
You could also do
#property (nonatomic, retain)AController *aController;
...
self.aController= [[AController alloc] init];
[aController release];
with a retaining property, and it would function the same way, but its better to use the other way (for retaining properties) because it's less confusing, that code makes it look like you assign aController and then it gets deleted from memory, when actually it doesn't because setAController retains it.