This is my code,
import <Foundation/Foundation.h>
@interface SyncObjectInfo : NSObject
{
NSString *strName;
}
@property(nonatomic,retain) NSString *strName;
-(void)returnRetainCount;
@end
#import "SyncObjectInfo.h"
@implementation SyncObjectInfo
@synthesize strName;
-(void)returnRetainCount
{
self.strName=@"name";
strName=@"name";
NSLog(@"Que-1. what is the retainCount of self.strName = ___");
NSLog(@"Que-2. what is the retainCount of strName = ___");
[self.strName retain];
NSLog(@"Que-3. what is the retainCount of self.strName= ___");
}
@end
I have a confusion for the retain count so...
Please give me the answer for the questions(1,2,3) of -(void)returnRetainCount
method? and please explain why?
Thanks
I just modified your example to add calls to retainCount
in your NSLog
statements. It should be noted that retainCount
isn't a particularly useful method and should generally be avoided.
See http://whentouseretaincount.com for more information (don't forget to scroll down for more details).
Anyway, here is what I ran. Note that I changed [self.str retain]
to [self.strName retain]
:
#import <Foundation/Foundation.h>
@interface SyncObjectInfo : NSObject
{
NSString *strName;
}
@property(nonatomic,retain) NSString *strName;
-(void)returnRetainCount;
@end
@implementation SyncObjectInfo
@synthesize strName;
-(void)returnRetainCount
{
NSLog(@"Que-1. what is the retainCount of self.strName = %lu", [self.strName retainCount]);
NSLog(@"Que-2. what is the retainCount of strName = %lu", [strName retainCount]);
[self.strName retain];
NSLog(@"Que-3. what is the retainCount of self.strName= %lu", [self.strName retainCount]);
}
@end
int main(int argc, char *argv[]) {
@autoreleasepool {
SyncObjectInfo *obj = [SyncObjectInfo new];
[obj returnRetainCount];
}
}
In all cases the answer is 0. This is to be expected because strName
is nil
and messages sent to nil
are ignored, so the call to [self.strName retain]
is ignored.
However, if I set strName
to something, using the following code:
int main(int argc, char *argv[]) {
@autoreleasepool {
SyncObjectInfo *obj = [SyncObjectInfo new];
obj.strName = @"Something";
[obj returnRetainCount];
}
}
Then when I rerun I get the following:
Que-1. what is the retainCount of self.strName = 18446744073709551615
Que-2. what is the retainCount of strName = 18446744073709551615
Que-3. what is the retainCount of self.strName= 18446744073709551615
The retain count is 18446744073709551615. This is because NSString
s are handled differently from most objects. This is one of the reasons why retainCount
isn't very useful.
If we change the NSString
to an NSURL
as follows:
@interface SyncObjectInfo : NSObject
{
NSURL *strName;
}
@property(nonatomic,retain) NSURL *strName;
// snip
int main(int argc, char *argv[]) {
@autoreleasepool {
SyncObjectInfo *obj = [SyncObjectInfo new];
obj.strName = [NSURL URLWithString:@"http://stackoverflow.com"];
[obj returnRetainCount];
}
}
and rerun we get:
Que-1. what is the retainCount of self.strName = 2
Que-2. what is the retainCount of strName = 2
Que-3. what is the retainCount of self.strName= 3
The first two cases are the same. The object returned by +URLWithString
is retained but autoreleased and then assigned to the property and retained again. At some point in the future the autorelease pool will be flushed and the retain count will drop to 1.
The third value as we expect has gone up by one because of the explicit call to retain
.
Your understanding from the Apple documentation that the retain count should be 1 (rather than 2 in questions 1 & 2) is technically incorrect but conceptually correct. The object has been autoreleased (effectively a promise that the object will be released in the near future).
We can investigate the effects of the autorelease pool by flushing the pool. I have modified the main
function to flush the autorelease pool before calling returnRetainCount
.
int main(int argc, char *argv[]) {
@autoreleasepool {
SyncObjectInfo *obj;
@autoreleasepool {
obj = [SyncObjectInfo new];
obj.strName = [NSURL URLWithString:@"http://stackoverflow.com"];
}
[obj returnRetainCount];
}
}
This time the output is:
Que-1. what is the retainCount of self.strName = 1
Que-2. what is the retainCount of strName = 1
Que-3. what is the retainCount of self.strName= 2
This is more what you'd expect. So what is happening?
When the NSURL
object is created by the URLWithString
method it has a retain count of 1. However, the NSURL
class needs to give up ownership of the object. If it called release
on this object before returning it the retain count would reach 0 and the object would be deallocated before it is ever returned.
Instead the URLWithString
method calls autorelease
on the object. Autorelease adds the object to the autorelease pool. Basically, NSURL
passes ownership to the autorelease pool with the understanding that the autorelease pool will release the object at some point in the near future (in an application the pool is flushed as part of the runloop cycle).
In the example above the object returned by URLWithString
has a retain count of 1. Assigning it to the property increments the retain count by 1 (so it is now 2). We then flush the autorelease pool (by leaving the scope of the @autoreleasepool { }
block and the retain count drops back to 1.