views:

4496

answers:

5

I'm looking over Apple's sample application EditableDetailView, and noticed that in one of their controllers, they're setting an instance of NSString property with (nonatomic, copy). When would one use copy instead of retain? Is this so they can make a unique copy without affecting the existing data?

+13  A: 

Yes, it's so that it can make a unique copy without affecting the existing data. The synthesized setters essentially look like this:

// For @synthesize(nonatomic, retain) foo:
- (void) setFoo(NSFoo *theFoo)
{
    [theFoo retain];  // retain new value
    [foo release];    // release old value, if any
    foo = theFoo;     // assign new value
}

// For @synthesize(nonatomic, copy) foo:
- (void) setFoo(NSFoo *theFoo)
{
    NSFoo* newFoo = [theFoo copy];  // make copy
    [foo release];  // release old value, if any
    foo = newFoo;   // assign new value
}

Note the order of operations here is important - the new value must be retained/copied before the old value is released, in case of self-assignment. If you released first and then assigned the property to itself, you might deallocate the value by accident. Also note that if the old value is nil, sending it a release message is ok, since sending a message to a nil object is explicitly allowed and does nothing.

The choice of retaining versus copying just determines whether or not the object's property shares the same value with what you're setting it to. Consider the following code:

// suppose the 'foo' property is declared 'retain' and the 'bar' property is
// declared 'copy'
NSFoo *foo = ...;
NSBar *bar = ...;
someObject.foo = foo;
someObject.bar = bar;
[foo changeInternalState];  // someObject.foo also changes, since it's the same object
[bar changeInternalState];  // someObject.foo does NOT change, since it's a copy
Adam Rosenfield
there might be a typo in your last line.where //someObject.foo does NOT... should be //someObject.bar does NOT
Michael Z
+2  A: 

Remember that there is an NS*Mutable*String. It would be really bad to be able to mutate the contents of a string that some other object owns (say, by deleting half its characters), especially if you don't realize you're affecting another object. Therefore, it's nice for the other object to make its own copy.

You may say “well, why don't I just copy the string before assigning it there?”. Maybe the object wants a mutable string and yours is immutable. If you have to copy the string first, then you have to look up which kind of string it wants in its documentation or header, then make the right kind of copy (every time). This way, you just say other.string = myString and it makes whatever kind of copy it wants—you don't have to worry about it.

Peter Hosey
A: 

instead of writing:

- (void) setFoo(NSFoo *theFoo)
{
    NSFoo* newFoo = [theFoo copy];  // make copy
    [foo release];  // release old value, if any
    foo = newFoo;   // assign new value
}

is it possible to write-???

- (void) setFoo(NSFoo *theFoo)
{
    [foo release];
    foo = [theFoo copy];  // make copy
}
russell
As Adam notes in his response, "Note the order of operations here is important - the new value must be retained/copied before the old value is released, in case of self-assignment." Also, if you indent your code with four spaces you'll get the pretty-printing. I've fixed it for you.
Stephen Darlington
Use comments / editing your question instead of adding an answer.
Georg
removed edits..
Michael Z
A: 

did you mean that i have to copy 'the foo' object before releasing 'foo'??but whats the problem if i relaese 'foo' before copying 'the foo'??because they are two different object i can't understand why releasing one affect other!!!!

and I need some easy and simple explanation about delegate.i read a lot about it but none of them gave a precise idea.

russell
If you have a follow up question you should post it asa new question, not as an answer to this old question. You of course can always link back to this page for reference if you want to.
sth
A: 

(For some reason, this post is appearing above the follow-up question I am trying to answer) Re:

did you mean that i have to copy 'the foo' object before releasing 'foo'??but whats the problem if i relaese 'foo' before copying 'the foo'??because they are two different object i can't understand why releasing one affect other!!!!

Most of the time, you are correct. If they are, in fact, two separate objects, it won't matter. The problem lies in the possibility that you are assigning the same object back into itself. If you were to say

[myObject setFoo: moof];
[myObject setFoo: moof];

Then the second time you did it, you would release moof before you copied it. In the intervening moment, it is possible that if moof's retain count went to zero then moof would be deleted, and you would have nothing to copy in the following step. Foo would now be nil.

Is this likely to happen? Probably more than you might think. There are certainly times when the user might click on an "update" button twice, for example.

I hope this is understandable and helpful.

HGHowe