Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSString Address issue

Tags:

objective-c

I'm trying to print address to string but i'm getting different address in first NSLog & same address in second NSLog. So could you tell me how is this happing. Its really confusing me. Thanks a lot in advance for your efforts.

NSString *str1 = [[NSString alloc] init];
NSString *str2 = [[NSString alloc] init];
NSString *str3 = [[NSString alloc] init];

NSLog(@"str1 = %p , str2 = %p, str3 = %p",&str1,&str2,&str3);
NSLog(@"str1 = %p , str2 = %p, str3 = %p",str1,str2,str3);

Output

str1 = 0x7fff565b9c88 , str2 = 0x7fff565b9c80, str3 = 0x7fff565b9c78
str1 = 0x10c0a7060 , str2 = 0x10c0a7060, str3 = 0x10c0a7060

I don't understand why str1, str2, and str3 all point to the same memory location.

like image 825
Dharmbir Singh Avatar asked Jun 26 '15 10:06

Dharmbir Singh


2 Answers

And why should str1, str2, str3 all reside at different memory addresses? They're all the same immutable string.

See bbum's comment here:

Right... one implementation detail of relevant interest (but, by no means, invalidates the answer in anyway); [[NSString alloc] initWithString:@"Hello world"] won't actually create a string on the heap. It'll just return the __NSCFConstantString (or whatever it is called) that was laid down in the mach-o file by the compiler. It is merely an interesting detail in that it does not change anything about your consumption of said string; it should be treated just like any other object.

Emphasis mine.

What's going on here is that when the compiler can determine at compile time what an immutable NSString object will be, it's creating that string differently. As bbum states, ultimately it's an implementation detail that you shouldn't worry about when you're writing your program.

But the side effect of this means that the compiler is able to make my program more memory efficient because it is able to find all of these instances and make all of my NSString pointers that it knows are supposed to be holding the same immutable value all point to the same single memory address.

We can probably achieve the same result with the following:

NSString *str1 = [[NSString alloc] init];
NSString *str2 = [NSString new];
NSString *str3 = [[NSString alloc] initWithString:@""];
NSString *str4 = [NSString stringWithString:@""];
NSString *str5 = @"";

These are all effectively the same thing.

However, if we create another string:

NSString *str6 = [NSString stringWithFormat:@"%@", @""];

This will (most likely... last time I checked) end up with a different value if we print str6 as a pointer.

And there are other ways to generate immutable NSString objects that don't get optimized like this at compile time. The point here is that if the compile can know at compile time what the string is going to be, it will create a __NSCFConstantString in the background that's outside of memory management, and it will point to that single instance whatever it can. Once it gets to run time, it will only point anything else to this if you point it there directly (str6 = str1). Otherwise, it's not going to waste execution time trying to determine if the strings are equal. If a new NSString happens to be equal and it wasn't happened at compile time, it will just be handled by ARC.

The compiler isn't able to determine that str6 is the same immutable string as the others. This is only a build time implication that the others all ended up with the same address.

Another interesting thing to note is that you will never see dealloc called on the __NSCFConstantString the compiler is creating for the variables declared in the way you declared them. So the compiler is not only making your code more efficient from a memory stand point, it's also removing all of the memory management code involved in keeping up with these strings.

like image 127
nhgrif Avatar answered Sep 21 '22 01:09

nhgrif


The first call to NSLog is printing the addresses of the 3 local variables str1, str2 and str3. They are all residing on the stack because they are local, hence the large addresses.

The second NSLog call is printing the addresses of the objects pointed to by str1, str2 and str3, which in this case has been optimised to the same object.

Your local variables are already pointers to NSStrings, not actual NSStrings themselves, so you don't need the address operator &.

like image 43
Charlie Scott-Skinner Avatar answered Sep 23 '22 01:09

Charlie Scott-Skinner