Search code examples
iosretaincount

NSString Retain Count


Whats the retain count of the NSString in the below mentioned Code snippet?

self.a = @"abcd"; // self.a is a NSString with (nonatomic, Strong) Attributes

NSLog(@"Retain Count of A == %d",(int)[self.a retainCount]);

self.b = self.a;// self.b is a NSString with (nonatomic, Strong) Attributes

NSLog(@"Retain Count of A == %d",(int)[self.a retainCount]);
NSLog(@"Retain Count of B == %d",(int)[self.b retainCount]);

[self.a release];

NSLog(@"Retain Count of A == %d",(int)[self.a retainCount]);
NSLog(@"Retain Count of B == %d",(int)[self.b retainCount]);


//Similarly whats the retain count if:
self.b = [self.a retain];

Solution

  • @"abcd" is a string literal. It is stored as a constant. If you were to log [@"abcd" class] then you'd get __NSCFConstantString (though such is an empirical observation; the class name is not guaranteed). retain, release, etc are no-ops on a constant string as it inherently has the same lifetime as the application. In practice, as vikingosegundo says, you get NSUIntegerMax.

    You're using properties so what will actually happen depends on your property type.

    With self.b = self.a what you'd expect is:

    • the getter self.a returns [[string retain] autorelease], so retain count is incremented for the lifetime of the current autorelease pool;
    • the setter self.b = retains the string, so the retain count is incremented again, for the lifetime of selfs ownership of the string.

    So two increments if you check during the lifetime of the autorelease pool, one long-term increment.

    Manual calls to retain and release do exactly what you'd think.

    Under ARC you don't manually get to call any of these things, including retainCount and the various retains and releases may be optimised out. A famous case is that something in the autorelease pool that is subsequently retained can be removed from the pool. So self.b = self.a may end with the retain count up by only one and the string not sitting in the autorelease pool, if the optimiser feels like it.

    The rule when using manual reference counting is fairly simple:

    • if you have an owning reference — one returned by a new, alloc, retain or copy — then release or autorelease the reference;
    • if you have a non-owning reference — i.e. any other sort, most commonly though that'll be from a vanilla getter — then don't release the reference. But don't necessarily expect it to be valid beyond the lifetime of the current autorelease pool.

    The return [[a retain] autorelease] pattern comes from the observation that self may have a shorter lifetime than the pool.