0

here is the following program about increasing d retain count value of a NSString type variable in interface part I have declared

@property (strong,nonatomic)NSString *str1;
@property (strong, nonatomic)NSString *str2;
-(IBAction)goBtn:(id)sender;

and ind implementation part I have defined following

- (IBAction)goBtn:(id)sender {
   self.str1=[[NSString alloc]init];
   self.str1=self.str2;
   self.str2=[self.str1 retain];
   self.str2=[[NSString alloc]init];
   self.str2=self.str1;
   self.str1=[self.str2 retain];
   self.str2=[self.str1 retain];
   NSLog(@"retain count is %i", self.str1.retainCount);
   NSLog(@"retain count of str2 is %i", self.str2.retainCount);
}

but the output is retain count is 0 retain count of str2 is 0

why is this happening?? is there anything wrong in codes???

giorashc
  • 13,691
  • 3
  • 35
  • 71
Arun Kumar
  • 788
  • 5
  • 15

2 Answers2

2

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.

Sven
  • 22,475
  • 4
  • 52
  • 71
  • good catch on the nil. I assumed that he set it elsewhere. When I look at that code block I just see desperation. – Cameron Lowell Palmer Jul 27 '13 at 08:02
  • sorry sir, but when I am not overwriting my new string with nil mean when self.str1=self.str2; or vise versa is not used, it's output always be -1. why is this so?? Can retain count ever be negative??? – Arun Kumar Jul 29 '13 at 03:56
  • No, the retain count cannot be negative, it is an unsigned integer. If you get a negative one you're printing it as a signed integer. The bit pattern of the signed integer -1 interpreted as an unsigned integer will give the biggest possible value (for a given bit size). Try printing it with `%u` instead of `%i`. – Sven Jul 29 '13 at 21:43
  • okkkkkkk... now i got it.. – Arun Kumar Jul 30 '13 at 10:40
0

Retain count is meaningless. Don't worry about it. It gets into a lot of complicated factors like the fact that NSString is a class cluster and the implementation details are really not your problem.

More importantly, your property is declared incorrectly.

Automatic Retain Count (ARC)

@property (strong, nonatomic) NSString *ARCString;

Retain/Release

@property (retain, nonatomic) NSString *retainString;

Further discussion

As Sven (below) points out retain and strong are synonymous technically. However, I think it is important to distinguish when code is under ARC or Retain/Release. Some general best practices:

Only refer to the ivar in init and dealloc using _ivar and here use a call to retain/release if not using ARC. No need for dealloc under ARC.

- (id)initWithString:(NSString *)string
{
   self = [super init];
   if (self != nil) {
      _retainString = [string retain]; // Adds 1 to retain count
   }

   return self;
}

- (void)dealloc
{
   [_retainString release]; // Decrement retain count by 1

   [super dealloc]; 
}

The rest of the time make the call to the getter/setter using self.ivar. This takes care of the correct behavior automatically.

- (void)doSomethingWithString:(NSString *)string
{
   self.retainString = string; // Adds 1 to retain count
}

If and when you decide to override the getter/setter in your declared property, then you will refer to the _ivar and manually call retain or release. If using ARC the call to retain/release is unnecessary.

- (void)setRetainString:(NSString *)string
{
    if (_retainString != string) {
       [_retainString release];
       _retainString = [string retain];
    }
}

You should always Analyze your code to verify you haven't screwed something up in an obvious way. It will often reveal failures in your logic.

Cameron Lowell Palmer
  • 21,528
  • 7
  • 125
  • 126
  • 1
    strong and retain are synonyms, that is not a problem. – Sven Jul 27 '13 at 07:18
  • @Sven It is stylistically disastrous. He is quite possibly confusing the underlying concepts and the distinction is incredibly important. – Cameron Lowell Palmer Jul 27 '13 at 07:21
  • Can be confusing for beginners, but once you know how the system works this should not be a problem. After all the reference counting mechanism doesn't go away with ARC. Of course you always should write `strong` for new ARC code, but if you are using older code that was written for manual memory management and converted to ARC later you'll almost always see both. – Sven Jul 27 '13 at 07:50
  • String properties should be copy. That init method is gonna do very bad things if passed a mutable string..... – bbum Jul 27 '13 at 14:28
  • Yes, if you are the habit of passing mutable strings. However, the point here was simply to demonstrate retain and release. Copy and the implementation of copy in objects is a whole 'nother kettle of fish. – Cameron Lowell Palmer Jul 27 '13 at 14:37