a base use of Objective-C's retainCount

132 Views Asked by At

We both know that the retain method will +1 retainCount, release will -1 retainCount, if retainCount == 0, the object dealloc. But I meet a problem, the following code run have the ridiculous result

#import <Foundation/Foundation.h>
@interface Person : NSObject
@property(nonatomic, retain) NSString *name;
@property(nonatomic, assign) NSInteger age;

@end

@implementation Person
- (id)init
{
    self = [super init];
    if (self) {
        self.name = @"name";
        self.age = 20;
    }
    return self;
}

- (void)dealloc
{
    NSLog(@"dealloc");
    [super dealloc];
}
@end

int main(int argc, const char * argv[])
{
    Person *per1 = [[Person alloc] init];
    NSLog(@"retainCount = %lu -- 1",[per1 retainCount]);
    [per1 release];
    [per1 retain];
    NSLog(@"retainCount = %lu -- 2",[per1 retainCount]);
    return 0;
}

The result is:

2014-01-11 21:56:23.887 blockTest[1287:303] retainCount = 1 -- 1
2014-01-11 21:56:23.889 blockTest[1287:303] dealloc
2014-01-11 21:56:23.889 blockTest[1287:303] retainCount = 2 -- 2

I don't use the ARC. Why I get this result? Isn't the app should crash?

3

There are 3 best solutions below

2
On

You shouldn't ever expect that this property returns any meaningful result.
It doesn't matter what you do, it's not your job.

See this for more information whentouseretaincount.com

2
On

Once an object is deallocated, you cannot send any further messages to that object. In your case, your object is deallocated once you send the release message to it. Sending any further messages, including retain and retainCount, is undefined behavior.

For example, on my system, the following code:

int main(int argc, const char * argv[])
{
    Person *per1 = [[Person alloc] init];
    [per1 release];
    Person *per2 = [[Person alloc] init];
    per2.name = @"Something Else";
    [per1 retain];
    NSLog(@"per1.name = %@",per1.name);
    return 0;
}

prints:

per1.name = Something Else

More undefined behavior!

0
On

What's happening here is that although the object has been deallocated, the memory where it's stored hasn't been overwritten yet, so the later calls still work because the data is temporarily still there.

The reason you get a retainCount of 2 at the end is that when you send release to an object with a retainCount of 1, they just dealloc the object straight away without bothering to decrement the internal count to zero.