Problem with NSString Address

I am trying to print the address in a string, but I get a different address in the first NSLog and the same address in the second NSLog. So you could tell me how this happens. It really bothers me. Thanks so much 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); 

Exit

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

I do not understand why str1 , str2 and str3 all point to the same memory location.

+4
objective-c
source share
4 answers

And why are str1 , str2 , str3 all located at different memory addresses? They are still immutable.

See bbum's comment here :

That's right ... one detail of the implementation of the relevant interest (but does not cancel the answer in any case); [[NSString alloc] initWithString:@"Hello world"] will not actually create a line on the heap. It will simply return the __NSCFConstantString compiler (or whatever it is called), which was laid down in the mach-o file by the compiler. This is just an interesting detail, since it does not change anything regarding your consumption of the mentioned line; it should be considered in the same way as any other object.

Emphasis on mine.

What happens here is that when the compiler, at compile time, can determine what an immutable NSString object will be, it creates this line in different ways. As bbum says, this is ultimately an implementation detail that you should not worry about when you write your program.

But a side effect of this means that the compiler is able to make my program more memory efficient, as it can find all of these instances and make all of my NSString pointers, which she knows should contain the same immutable value, point to the same same 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 = @""; 

This is all the same.

However, if we create another line:

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

This will (most likely ... the 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 are not optimized this way at compile time. The point here is that if the compiler can find out what will be on this line at compile time, it will create an __NSCFConstantString in the background outside of memory management, and it will point to that single instance, whatever it is. Once it gets to runtime, it will point to something else if you specify it directly ( str6 = str1 ). Otherwise, he is not going to waste time executing, trying to determine if the lines are equal. If the new NSString is equal, and this did not happen at compile time, it will just be processed by ARC.

The compiler cannot determine that str6 is the same immutable string as the rest. It is just a build time value that the rest all have the same address.

Another interesting thing: you will never see a dealloc called by __NSCFConstantString that the compiler creates for variables declared the way you declared them. Therefore, the compiler not only makes your code more efficient in terms of memory, but also removes all the memory management code associated with maintaining these lines.

+5
source share

The first call to NSLog is to print the addresses of the three local variables str1, str2, and str3. All of them are on the stack because they are local, therefore large addresses.

The second call to NSLog prints the addresses of the objects pointed to by str1, str2 and str3, which in this case have been optimized for the same object.

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

+2
source share

Interestingly, you got the result, but it makes sense str1, str2, str3 - all are immutable, and therefore they will never change, and they all have the same content, so instead of getting 3 new NSString you have the same three times, If you change them to NSMutableStrings, you will get the expected result. I played around a bit with this and I found that if you enable ARC and add this

 NSLog(@"str1 = %lu , str2 = %lu, str3 = %lu", [str1 retainCount], [str2 retainCount], [str3 retainCount] ); 

you will get some more interesting things, I expected to see the value 3, three times, to represent three selections for the same object, but instead you get 18446744073709551615, which makes sense when you also add this

 NSLog(@"str1 = %@ , str2 = %@, str3 = %@", [str1 class], [str2 class], [str3 class] ); 

You will see that the __NSCFConstantString class, which is not a reference, counts its equivalent with a literal string.

You can get a similar thing with a lot of c compilers, where if you define a literal string c, for example

  char * cstr1 = "abc"; char * cstr2 = "abc"; printf( "cstr1 == cstr2 = %s\n", cstr1 == cstr2 ? "true" : "false" ); 

You can see that the compiler saved memory for literals, having only "abc" and pointing all the pointers to the same place.

Thinking about this a bit, the init method for NSString might look something like this.

 - (instancetype)init { [self release]; return @""; } 
+1
source share

str1 - string memory address

& str1 - memory address of a pointer to a string

(maybe the other way around)

0
source share

All Articles