andrewmc
andrewmc

Reputation: 37

Reference vs. Copy with Obj-C NSString

I did find some discussion on this topic, but it was beyond my current level of understanding. I'm reading through Kochan's "Programming in Objective-C, 4e" and am on the section about NSString objects. First, the code I'm playing with so I can ask my question:

NSString *strA = @"StringA";
NSString *strB = @"StringB";
NSLog(@"Value of strA: %@",strA);
NSLog(@"Value of strB: %@",strB);

strB = strA; // strB should point to strA's memory location
NSLog(@"New value of strB: %@",strB); //correctly logs as "StringA"
strA = @"StringA has been changed.";
NSLog(@"New value of strB: %@",strB); //logs as "StringA" still
NSLog(@"New value of strA: %@",strA); //correctly logs as "StringA has been changed"

My understanding is that saying strB = strA would mean that strB is pointing to strA's memory location, so any changes to strA would also go to strB. However, this doesn't happen. Kochan says it's supposed to, and to get around it suggests using

strB = [NSString stringWithString: strA];

From what I can see, either method works. I can say strB = strA, then change strA, yet strB still retains the value it received (the value of strA before just changing it).

I thought this might come from NSString being immutable, but if that's the case, why can I in fact change the values of str1 and str2 after initialization? What am I missing here? Thanks.

Upvotes: 0

Views: 255

Answers (4)

rob mayoff
rob mayoff

Reputation: 385580

As if you didn't have enough answers to this already...

I think a diagram or three will help you understand what's going on in your code example.

First, your code does this:

NSString *strA = @"StringA";
NSString *strB = @"StringB";

This makes your app's memory look like this:

memory diagram 1

On the left are your local variables, strA and strB. They are just pointers to objects in memory.

In the middle are the string objects. These are pre-created in your app by the compiler because they appeared in your source code.

On the right are the actual characters of the string objects. These are also pre-created in your app by the compiler.

Next, your code does this:

strB = strA;

Now your app's memory looks like this:

memory diagram 2

Notice that your local variable, strB, changed, but the objects and the characters didn't change.

Finally, your code does this:

strA = @"StringA has been changed.";

This makes your app's memory look like this:

memory diagram 3

Your local variable, strA, has changed, but the objects and the characters still didn't change.

Upvotes: 3

Caleb
Caleb

Reputation: 124997

My understanding is that saying strB = strA would mean that strB is pointing to strA's memory location, so any changes to strA would also go to strB.

Yes, although it might be more clear to say that strB and strA will both point to the same object.

I can say strB = strA, then change strA, yet strB still retains the value it received (the value of strA before just changing it).

If you change strA, then you're necessarily making strA point to a different string. NSStrings are immutable, so you can't change them -- you can only replace them. So, if you say something like:

strA = [strA stringByAppendingString:@"foo"];

then strA no longer points to the original string. strB still points to the original, of course, and that object remains unchanged, so the string pointed to by strA and the one pointed to by strB are different objects.

What am I missing here?

I think you're thinking that the new object is created when you do the assignment strB = strA;, but in reality both pointers will point to the same object after that statement. It's when you "change" strA that a new object is created.

Now, things would be different if you were talking about mutable strings, which you can of course change. Then you'd have a situation like this:

NSMutableString *mstrA = [@"foo" mutableCopy];
NSMutableString *mstrB = mstrA;     // now mstrB points to the same object as mstrA
[mstrA appendString:@"bar"];
NSLog(@"%@", mstrB);                // will log @"foobar" because the string actually changed

Upvotes: 1

jscs
jscs

Reputation: 64002

There's two ways to think about what's happening here. One, slightly more low-level, is that you're dealing with a construct called a pointer. A pointer holds a memory address, in exactly the same way that an int variable holds an integer value. If you assign an int to another int, then change the first, the second does not change:

int i1 = 10;
int i2 = i1;
i1 = 600;    // i2 still 10

The same is true of pointers.

The other (possibly more productive) way to think of it is that strA and strB are actually names for objects. If you assign an object via one name to another name, then both names hold the same object. Issues of memory management and object lifetime aside, you can then re-assign one name to a different object, and the other will continue to point to the original object.

Upvotes: 0

user529758
user529758

Reputation:

My understanding is that saying strB = strA would mean that strB is pointing to strA's memory location, so any changes to strA would also go to strB.

Changes to strA's memory location -- yes. Changes to a completely unrelated pointer to the same location, which now points to somewhere else -- no.

Upvotes: 0

Related Questions