{"id":281,"date":"2009-03-17T01:25:29","date_gmt":"2009-03-17T06:25:29","guid":{"rendered":"http:\/\/vgable.com\/blog\/2009\/03\/17\/mutable-property-and-copy-gotcha\/"},"modified":"2009-03-17T01:53:42","modified_gmt":"2009-03-17T06:53:42","slug":"mutable-property-and-copy-gotcha","status":"publish","type":"post","link":"https:\/\/vgable.com\/blog\/2009\/03\/17\/mutable-property-and-copy-gotcha\/","title":{"rendered":"Mutable @property and Copy Gotcha"},"content":{"rendered":"<p>If you have a <code><a href=\"http:\/\/developer.apple.com\/DOCUMENTATION\/Cocoa\/Conceptual\/ObjectiveC\/Articles\/ocProperties.html#\/\/apple_ref\/doc\/uid\/TP30001163-CH17-SW13\">@property<\/a><\/code> for an object who&#8217;s name starts with <code>NSMutable<\/code>, and you use the <code>copy<\/code> declaration attribute, then <strong>the code that is synthesized for you is not correct.<\/strong>  Because it uses <code>copy<\/code>, not <code>mutableCopy<\/code>, to do the copy during assignment, the value will <em>not<\/em> be mutable.<\/p>\n<p>Here&#8217;s a demonstration,<\/p>\n<pre>\n@interface Gotcha : NSObject {\n\tNSMutableString *mutableString;\n}\n@property (copy) NSMutableString *mutableString;\n@end\n@implementation Gotcha\n@synthesize mutableString;\n@end\n<br>...\nGotcha *x = [[[Gotcha alloc] init] autorelease];\nx.mutableString = [NSMutableString stringWithString:@\"I am mutable.\"];\n[x.mutableString appendString:@\" Look at me change.\"]; \n<\/pre>\n<p>It crashes with the message,<\/p>\n<blockquote><p>*** Terminating app due to uncaught exception &#8216;NSInvalidArgumentException&#8217;, reason: &#8216;Attempt to mutate immutable object with appendString:&#8217;<\/p><\/blockquote>\n<h3><code>copy<\/code> vs <code>mutableCopy<\/code><\/h3>\n<p>The <a href=\"http:\/\/developer.apple.com\/documentation\/Cocoa\/Reference\/Foundation\/Classes\/NSObject_Class\/Reference\/Reference.html#\/\/apple_ref\/occ\/instm\/NSObject\/copy\"><code>copy<\/code><\/a> method returns an <em>immutable<\/em> copy of an object, even if the object is mutable. Eg the <code>copy<\/code> of an <code>NSMutableString<\/code> is an immutable <code>NSString<\/code>.<\/p>\n<p>The <a href=\"http:\/\/developer.apple.com\/documentation\/Cocoa\/Reference\/Foundation\/Classes\/NSObject_Class\/Reference\/Reference.html#\/\/apple_ref\/occ\/instm\/NSObject\/mutableCopy\"><code>mutableCopy<\/code><\/a> method returns a mutable copy of an object, even if the object is not mutable.  Eg., the <code>mutableCopy<\/code> of an <code>NSString<\/code> is an <code>NSMutableString<\/code> object.<\/p>\n<p><code>@synthesize<\/code> always uses <code>copy<\/code> in the setters it generates. That means an <em>immutable<\/em> copy will always be stored, even if an <code>NSMutable<\/code> object is given.<\/p>\n<h3>Workarounds<\/h3>\n<p><a href=\"http:\/\/developer.apple.com\/DOCUMENTATION\/Cocoa\/Conceptual\/ObjectiveC\/Articles\/ocProperties.html#\/\/apple_ref\/doc\/uid\/TP30001163-CH17-SW32\">Apple says<\/a>, &#8221; &#8230;In this situation, you have to <strong>provide your own implementation of the setter method<\/strong>..&#8221;  (To me, this isn&#8217;t as satisfying of an answer as a <code>mutablecopy<\/code> attribute.  But it&#8217;s what Apple has chosen, so all we can do is <a href=\"https:\/\/bugreport.apple.com\/\">file enhancement requests<\/a> and trust their reasoning).<\/p>\n<p>Another workaround is to <strong>make any property that is a mutable value <code>readonly<\/code><\/strong>.  If something is mutable, you can change it&#8217;s contents directly, so there is rarely a need to set it.  For example, with the <code>Gotcha<\/code> object, it&#8217;s just as easy to say<\/p>\n<pre>[x.mutableString setString:@\"New String\"];<\/pre>\n<p>as<\/p>\n<pre>x.mutableString = [NSMutableString stringWithString:@\"New String\"];<\/pre>\n<p>Finally, you might consider <strong>using an immutable <code>readwrite<\/code> property<\/strong>. In my experience, immutable objects are generally safer, and often faster (I owe you an article on this, but <a href=\"http:\/\/www.google.com\/search?rls=en-us&#038;q=immutable+objects&#038;ie=UTF-8&#038;oe=UTF-8\">there are plenty of articles on the benefits of immutability<\/a>).  I know this sounds like a smart-ass suggestion, and <em>it won&#8217;t be a good answer much of the time<\/em>.  But it&#8217;s surprising how often things turn out not to need mutability once a design matures.  Since reducing the mutability of an object often improves it, and it does work around the problem, it&#8217;s worth at least considering this solution.<\/p>\n<h3>Why not Just Use <code>retain<\/code>?<\/h3>\n<p>Changing the <code>copy<\/code> to <code>retain<\/code> well let you assign a mutable object, but I do not like the idea.  My article, <a href=\"http:\/\/vgable.com\/blog\/2008\/11\/14\/prefer-copy-over-retain\/\"><cite>Prefer <code>copy<\/code> Over <code>retain<\/code><\/cite><\/a> explains in detail.  My biggest worry is aliasing,<\/p>\n<pre>\nNSMutableString *aLocalString = [NSMutableString string];\nx.mutableString = aLocalString;\n[x doSomething];\n\/\/aLocalString might have been changed by doSomething!\n\/\/\n\/\/ 300 lines later...\n\/\/\n[aLocalString appendString:@\" now with more bugs!\"];\n\/\/x has been changed too!\n<\/pre>\n<p><strong>Using <code>retain<\/code> with <code>NSMutable<\/code> objects is asking for bugs.<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you have a @property for an object who&#8217;s name starts with NSMutable, and you use the copy declaration attribute, then the code that is synthesized for you is not correct. Because it uses copy, not mutableCopy, to do the copy during assignment, the value will not be mutable. Here&#8217;s a demonstration, @interface Gotcha : [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[18,6,5,4],"tags":[371,372,373,263],"class_list":["post-281","post","type-post","status-publish","format-standard","hentry","category-bug-bite","category-cocoa","category-objective-c","category-programming","tag-property","tag-synthesize","tag-nsmutable","tag-objective-c-20"],"_links":{"self":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/posts\/281","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/comments?post=281"}],"version-history":[{"count":0,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/posts\/281\/revisions"}],"wp:attachment":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/media?parent=281"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/categories?post=281"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/tags?post=281"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}