Is there any real point to the (copy) attribute in a property?
objective-c
Solution
`(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.
Problem
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?