William Hu
William Hu

Reputation: 16149

NSMutableString retain/copy are the same(copy doesn't work?)

I am testing copy/retain property under XCode 6.4 without ARC.

@property(nonatomic, retain) NSMutableString *retainString;
@property(nonatomic, copy) NSMutableString *copyedString;
@synthesize copyedString, retainString;



    NSMutableString *mStr = [NSMutableString stringWithFormat:@"abc"];
    retainString = mStr;
    copyedString = mStr;
    NSLog(@"mStr:%p",  mStr);
    NSLog(@"retainStr:%p", retainString);
    NSLog(@"copyStr:%p",   copyedString);

    [mStr appendString:@"de"];
    NSLog(@"retainStr:%@",  retainString);
    NSLog(@"copyStr:%@",    copyedString);

    [copyedString appendString:@"123"];
    NSLog(@"mStr:%@",  mStr);
    NSLog(@"copyStr:%@",    copyedString);
    NSLog(@"retainStr:%@",  retainString);

My questons:

  1. The copyedString should alloc a new space, the all the three strings has the same address.
  2. When mString was changed, copyedString shouldn't be changed(I know they are the same address now so changed)
  3. copyedString changed, mStr and retainString shouldn't be changed.

Am i make something wrong?

Here are the logs:

[10656:986440] mStr:0x7f871bd71340
[10656:986440] retainStr:0x7f871bd71340
[10656:986440] copyStr:0x7f871bd71340
[10656:986440] retainStr:abcde
[10656:986440] copyStr:abcde
[10656:986440] mStr:abcde123
[10656:986440] copyStr:abcde123
[10656:986440] retainStr:abcde123

EDIT oh yes, my mistake. self.property will call the setter and getter which means copy was used.

So the solution is change these two lines to:

self.retainString = mStr;
self.copyedString = mStr;

But i got this crash error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendString:'
*** First throw call stack:

Does copyedString become NSString ?

Upvotes: 2

Views: 86

Answers (2)

Leo
Leo

Reputation: 24714

You should use self to access copy property if you want to set value.

  NSMutableString *mStr = [NSMutableString stringWithFormat:@"abc"];

self.retainString = mStr;

self.copyedString = mStr;

NSLog(@"mStr:%p",  mStr);
NSLog(@"retainStr:%p", self.retainString);
NSLog(@"copyStr:%p",   self.copyedString);

[mStr appendString:@"de"];

NSLog(@"retainStr:%@",  self.retainString);
NSLog(@"copyStr:%@",    self.copyedString);

Log

2015-07-24 16:11:19.728 OCTest[13193:268356] mStr:0x7f84034ba020
2015-07-24 16:11:19.729 OCTest[13193:268356] retainStr:0x7f84034ba020
2015-07-24 16:11:19.729 OCTest[13193:268356] copyStr:0x7f84034bfa50
2015-07-24 16:11:19.729 OCTest[13193:268356] retainStr:abcde
2015-07-24 16:11:19.729 OCTest[13193:268356] copyStr:abc

In your way,it not copy,it just use pointer to access the address.So,it point to same address

Edit

If you want copy property return mutable result,delete the @synthesize,and rewrite

-(void)setCopyedString:(NSMutableString *)copyedString{
    _copyedString = [copyedString mutableCopy];
}

Upvotes: 1

trojanfoe
trojanfoe

Reputation: 122391

All of those variables are references to the same object:

NSMutableString *mStr = [NSMutableString stringWithFormat:@"abc"];
retainString = mStr;
copyedString = mStr;

So changes made via one reference are visible via the other references.

Using the = operator, in pretty much any language, does not imply a copy of the object, just a copy of the reference to that object (exception would be an overridden operator = in C++, but that's rarely ever done). This is different for primitive types, where the = operator does imply a copy.

What you want, I believe, is:

copyedString = [mStr mutableCopy];

and now copyedString is a different object.

Upvotes: 0

Related Questions