You are sending a lot of messages to nil and that is why you are getting a 0 for the retain count.
Here I wrote down your code again with the new values for your variables when they change:
str1 and str2 are nil
self.str1=[[NSString alloc]init];
str1 is empty string
self.str1=self.str2;
str1 is nil
self.str2=[self.str1 retain];
self.str2=[[NSString alloc]init];
str2 is empty string
self.str2=self.str1;
str2 is nil
self.str1=[self.str2 retain];
self.str2=[self.str1 retain];
In the end both str1 and str2 are nil giving you a zero retain count.
But even if you didn't overwrite your new strings with nil every time you wouldn't get the expected result. Lets consider this:
self.str1 = [[NSString alloc] init]
self.str2 = [[NSString alloc] init]
If you look at their retain count you'll get 18446744073709551615 (on Mac OS X, 64 bit) for each. If you then look at the values of the pointers you'll see that they both are equal, so you got the same empty NSString object both times you called [[NSString alloc] init]
.
That actually makes sense. NSString objects are immutable, that means once they are created they cannot ever change. So there is no point in wasting memory on multiple identical copies of the empty string.
Some of those shared instances return the biggest possible value from their retainCount method to show the fact that they are singletons. But not all of them.
So the retain count of objects is not very useful. Some objects lie about it. And in real apps it still often is not what you'd expect. Sometimes the system holds on to objects for some time, even if you didn't retain it yourself.
But I guess you are trying to learn how the retain/release memory model works (which is necessary, even if you are using ARC). For this you can get away with querying the retain count. But then you should use the base class NSObject
directly, because it doesn’t do any special tricks with the retain counter. And you need to keep in mind that as soon as you pass your test objects to some system methods your retain count could be something unexpected later. Always keep in mind to never query the retain count in a real app - it is useless.