5

I started a small Xcode project to investigate whether an NSMutableString property should be copy or retain. I declared my property with the copy attribute:

@property (nonatomic,copy) NSMutableString *stringA;

Then initialized it as self.stringA = [NSMutableString new];

finally tried to set a string [stringA setString:@"A"];.

However the program gives,

"Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with setString:'"

Is it because the resulting string is a NSString? Does this mean I should declare my NSMutableString properties using retain attribute and NSString properties using copy ?

jscs
  • 63,694
  • 13
  • 151
  • 195
rustylepord
  • 5,681
  • 6
  • 36
  • 49
  • 3
    You almost certainly do not want a mutable string as a property in the first place; at least, not one that is exposed as API. – bbum Aug 16 '12 at 18:02
  • my answer, in too many words: http://stackoverflow.com/questions/4995254/nsmutablestring-as-retain-copy/5004019#5004019 – justin Aug 16 '12 at 18:03
  • It's pointless to use `copy` for NSStrings. – Hot Licks Aug 16 '12 at 18:03
  • 2
    @HotLicks no it's not. remember semantics! what happens if a client passes a mutable string as a parameter to your class, you retain it, and then they mutate it behind your back? bad stuff. the simple solution is to make a copy -- if the parameter is mutable, then you have correctness, and a string you can easily pass without creating more copies. if it is immutable, then it could `return [self retain]` without making a deep copy. – justin Aug 16 '12 at 18:08
  • What I understood so far is copy is important in NSString but not in NSMutableString. Since NSMutableString is a subclass of NSString , therfore you can assign a NSMutableString to NSString. Correct me if I am wrong here. – rustylepord Aug 16 '12 at 18:12
  • @rustylepord well, it's not that it is not important -- the 'problem' is that `-[NSMutableString copy]` produces an *immutable* copy. for a mutable copy, you would use `mutableCopy`. `mutablecopy` is not a property specifier. so it's more like an edge case which is not supported by objc properties, and it's rarely useful or desirable. a mutable ivar, if really necessary, should typically be completely private. in most cases, immutable is the right choice. as well, you often don't want to retain a string you receive from an unknown source ; you will want to copy it because it may be mutable. – justin Aug 16 '12 at 18:45

2 Answers2

11

You're right, the copy method of NSMutableString returns an immutable NSString. This is a convention in Cocoa, it also applies to NSMutableArray, NSMutableDictionary, etc.

So if you want your property to remain mutable, you should declare it as retain. If you need copy semantics, but still want the result to be mutable, you'd have to implement your own setter for the property (and use mutableCopy to do the copying).

The reason you commonly see copy for string properties is that it's often desirable to have a guarantee that a string is immutable, regardless of what kind of string is assigned to the property. Otherwise you might end up accidentally modifying the same string elsewhere, which can be difficult to debug. Immutable objects also have the benefit of being thread-safe.

omz
  • 53,243
  • 5
  • 129
  • 141
  • SO basically I should use copy for NString, NSArray , NSDictionary types since there mutable variants and for the mutable types like NSMutableString , NSMutableArray I should use retain. Is this correct? – rustylepord Aug 16 '12 at 18:06
-1

The first question I would ask is how stringA was initialized. If you set it from a plain String then it may be why you are getting that. Copy and Retain actually performs differently and you should know why you would use one or the other.

Copy is actually making a copy of the memory so that any changes you do to that property do not affect the original it was set from where retain only increments the retain count of the memory so you ensure that it will not be released until you are done referencing it.

rooster117
  • 5,502
  • 1
  • 21
  • 19