I was playing around with memory (de)allocation stuff on a simple command line app for Mac OSX 10.7 built using Xcode Version 4.2.1 with ARC enabled, and the default build settings. I can't explain the behaviour I'm getting from what I understand about ARC, so I'm hoping someone can explain what's going on here.
First off, in the following code I'm getting the behaviour I expect (please note that the NLog() output is given in the comment after the corresponding statement)
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSObject *objPtr1 = [[NSObject alloc] init];
NSObject *objPtr2 = objPtr1;
__weak NSObject *weakRef = objPtr1;
NSLog(@"%@", [objPtr1 description]); // <NSObject: 0x1001107d0>
objPtr1 = nil;
NSLog(@"%@", [objPtr2 description]); // <NSObject: 0x1001107d0>
objPtr2 = nil;
NSLog(@"%@", [weakRef description]); // (null)
return 0;
}
So in the above, right after weakRef is assigned, the NSObject instance has two strong pointers to it, and therefore a retain count of 2. After zeroing objPtr1 there's still one retaining pointer to the instance, so it's still in memory and responds to the description message. After nil-ing objPtr2, there are no strong pointers to the object and it is deallocated (I'm assuming it is, since weakRef has been zeroed). So far, so good.
Now, the same code with a small change:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSObject *objPtr1 = [[NSObject alloc] init];
NSObject *objPtr2 = objPtr1;
__unsafe_unretained NSObject *weakRef = objPtr1; // __unsafe_unretained instead of just __weak
NSLog(@"%@", [objPtr1 description]); // <NSObject: 0x1001107d0>
objPtr1 = nil;
NSLog(@"%@", [objPtr2 description]); // <NSObject: 0x1001107d0>
objPtr2 = nil;
NSLog(@"%@", [weakRef description]); // <NSObject: 0x1001107d0>
//why was the object instance not deallocated and the preceding statement not crash the program?
return 0;
}
I was expecting weakRef to become a dangling pointer sending a message through which would cause the program to crash in the third NSLog() statement, but it seems the object instance is still alive and well.
Another thing I find weird:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSObject *objPtr1 = [[NSObject alloc] init];
NSObject *objPtr2 = objPtr1;
__weak NSObject *weakRef = objPtr1; // __weak again
NSLog(@"%@", [weakRef description]); // <NSObject: 0x1001107d0>
objPtr1 = nil;
NSLog(@"%@", [weakRef description]); // <NSObject: 0x1001107d0>
objPtr2 = nil;
NSLog(@"%@", [weakRef description]); // <NSObject: 0x1001107d0>
return 0;
}
This last code is like the first one (using the zeroed __weak pointer); the only difference is that the description message was sent to the object through weakRef in each of the three NSLog() calls. But this time round the object isn't deallocated even after the two strong references have been removed (since it's still responding to messages through weakRef).
So what's going on here?