Note that there are some explanatory texts on larger screens.

plurals
  1. POInconsistent object deallocation with ARC?
    primarykey
    data
    text
    <p>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.</p> <p>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)</p> <pre><code>#import &lt;Foundation/Foundation.h&gt; int main (int argc, const char * argv[]) { NSObject *objPtr1 = [[NSObject alloc] init]; NSObject *objPtr2 = objPtr1; __weak NSObject *weakRef = objPtr1; NSLog(@"%@", [objPtr1 description]); // &lt;NSObject: 0x1001107d0&gt; objPtr1 = nil; NSLog(@"%@", [objPtr2 description]); // &lt;NSObject: 0x1001107d0&gt; objPtr2 = nil; NSLog(@"%@", [weakRef description]); // (null) return 0; } </code></pre> <p>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 <strong>description</strong> 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.</p> <p>Now, the same code with a small change:</p> <pre><code>#import &lt;Foundation/Foundation.h&gt; 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]); // &lt;NSObject: 0x1001107d0&gt; objPtr1 = nil; NSLog(@"%@", [objPtr2 description]); // &lt;NSObject: 0x1001107d0&gt; objPtr2 = nil; NSLog(@"%@", [weakRef description]); // &lt;NSObject: 0x1001107d0&gt; //why was the object instance not deallocated and the preceding statement not crash the program? return 0; } </code></pre> <p>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.</p> <p>Another thing I find weird:</p> <pre><code>#import &lt;Foundation/Foundation.h&gt; int main (int argc, const char * argv[]) { NSObject *objPtr1 = [[NSObject alloc] init]; NSObject *objPtr2 = objPtr1; __weak NSObject *weakRef = objPtr1; // __weak again NSLog(@"%@", [weakRef description]); // &lt;NSObject: 0x1001107d0&gt; objPtr1 = nil; NSLog(@"%@", [weakRef description]); // &lt;NSObject: 0x1001107d0&gt; objPtr2 = nil; NSLog(@"%@", [weakRef description]); // &lt;NSObject: 0x1001107d0&gt; return 0; } </code></pre> <p>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).</p> <p>So what's going on here?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. COOK, it seems that in code #2 (with the unsafe unretained reference) if I insert an NSLog() statement (as a sort of filler) between "objPtr2 = nil" and "NSLog(@"%@", [weakRef description])" the program crashes sometimes (with an EXC_BAD_EXCESS error) and sometimes doesn't. If I insert another filler NSLog() statement, then the program definitely crashes (at least all the times I ran it). So I guess this means that reclaiming freed memory is not necessarily the absolute first thing that happens after an object loses all its strong references.
      singulars
    2. COcode #3 is still a puzzler for me, though... if I send a message to our instance via weakRef as in the code, then it doesn't seem to get deallocated even after all the strong references to it are removed - and not even when main() returns (I subclassed NSObject and overrode the dealloc method putting in an NSLog() to check whether it would be called - it wasn't). Seems like it might be a bug.
      singulars
    3. COThat does seem odd, yes. You're right about the code #2 - the memory just hasn't been re-used yet, so it still points to a "valid" `NSObject`, so `description` works fine. Code #3 is odd. I noticed it only doesn't zero `weakRef` if the 2nd `description` is sent to `weakRef`. i.e. if you send `description` to `weakRef` then `objPtr2` then `weakRef`, it does correctly output `(null)` for the last one.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload