I try to better understand memory management in Objective C (without ARC). Currently create simple program to try it in use.
My code
...
//create some object
RetainTracker * rt = [RetainTracker new]; //RC=1
NSLog(@"Just created - %lu", (unsigned long)[rt retainCount]);
[rt retain]; // RC=2
NSLog(@"%lu", (unsigned long)[rt retainCount]);
[rt release]; //RC=1
NSLog(@"%lu", (unsigned long)[rt retainCount]);
[rt release]; //RC=0 -> call to dealloc
//call to object rt again after it was deallocated and get RC=1
NSLog(@"%lu", (unsigned long)[rt retainCount]); //think that here must be exception ?
Result :
So, on result we can see that reference counter still equal to 1 after I release last reference and for object rt.
I go deeper, and investigate with Instruments "life" of this object, got next
As I understand:
[rt retain]
- RC=2;[rt release]
- RC=1;[rt release]
- RC=0;So, object must be deallocated, but if I call to [rt retainCount]
after step 4 I got that RC for this object still equal to 1. Why? Maybe I make somewhere mistake or miss something?
After the object is deallocated, using the pointer to the object results in undefined behavior. That is, it can print 1, 42, your program could crash, Hello Kitty could pop up on your computer; anything can happen. Any behavior is consistent with undefined behavior, even behavior that seems to indicate some other thing is happening.
Besides the fact that it's undefined behavior, what you see is very likely based on what you did. After an object is deallocated, its memory is marked as available for use, but the bytes that constituted the object in memory still remain there. So in the immediate time being, it is likely that it hasn't been overwritten with other stuff, and the memory will still "look" like the object that was deallocated, and sending messages to it (though undefined behavior) will likely succeed, because it simply uses the parts of the object that are still in the right place in memory.
As regarding the retain count, you are assuming that when you release
it, and the retain count (however it is stored in memory) will always be decremented, so that if before the release
it is 1, afterwards it should be 0. However, they don't have to do this when the retain count is 1, because they know that when you release
an object with retain count 1, the object will be deallocated, after which you are not supposed to use the object anyway, so they might as well skip decrementing it in this case, because there's no point in updating a variable that won't be used anymore.