0

In the following code, which is ARC'd and running 64-bit on Mac OS X 10.8.4, why is the instance of MyObj not being deallocated before the program terminates?

#import <Foundation/Foundation.h>

@interface MyObj : NSObject
@end

@implementation MyObj
- (void)dealloc
{
    NSLog(@"MyObj dealloc'd %p", self);
}
@end

int main(int argc, const char * argv[])
{
    MyObj* obj1 = [[MyObj alloc] init];
    __weak MyObj* weakObj1 = obj1;
    NSLog(@"Use it: %p\n", weakObj1);

    // Why isn't MyObj deallocated here?

    return 0;
}
Doug Richardson
  • 10,483
  • 6
  • 51
  • 77

2 Answers2

3

__weak relies on the Objective-C runtime function objc_loadWeak. From Objective-C Automatic Reference Counting in the documentation for Clang 3.4:

id objc_loadWeak(id *object);

Precondition: object is a valid pointer which either contains a null pointer or has been registered as a __weak object.

If object is registered as a __weak object, and the last value stored into object has not yet been deallocated or begun deallocation, retains and autoreleases that value and returns it. Otherwise returns null. Equivalent to the following code:

id objc_loadWeak(id *object) {
    return objc_autorelease(objc_loadWeakRetained(object));
}

Must be atomic with respect to calls to objc_storeWeak on object.

Rationale

Loading weak references would be inherently prone to race conditions without the retain.

Since objc_loadWeak requires an autorelease pool, then you must have an autorelease pool present when using __weak. The pool can created by either NSAutoreleasePool or @autoreleasepool. If an autorelease pool is not present, then nothing will release your object after objc_loadWeak retains it and your object will therefore never be deallocated.

Here is a fix for the code above:

#import <Foundation/Foundation.h>

@interface MyObj : NSObject
@end

@implementation MyObj
- (void)dealloc
{
    NSLog(@"MyObj dealloc'd %p", self);
}
@end

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        MyObj* obj1 = [[MyObj alloc] init];
        __weak MyObj* weakObj1 = obj1;
        NSLog(@"Use it: %p\n", weakObj1);

        // Now MyObj is deallocated
    }

    return 0;
}
Doug Richardson
  • 10,483
  • 6
  • 51
  • 77
1

weakObj1 is not going to be deallocated until main ends. When you are using ARC, which is what you should do, variables and objects won't be deallocated until the block where they were declared in ends. When this happens, all the objects that are not being strong referenced by any object will be deallocated.

Keep on mind that to deallocate an object a release message has to be sent to it. If you are using manual retain-release, MRR, you have to do it by yourself, if you are using automatic reference counting, ARC, the system will do it for you.

Diego A. Rincon
  • 747
  • 1
  • 8
  • 25
  • *"And object or variable will be deallocated once the block where it was declared ends"* - this is wrong. A *strong reference* will be released at the end of the block. The object will be deallocated if the last strong reference is release. But `__weak MyObj* weakObj1 = obj1;` creates a *weak reference* that does not increase the retain count. – Martin R Jun 21 '13 at 06:40
  • weakObj1 have weak reference to obj1, which means weakObj1 won't increase obj1 retain count; but it doesn't mean that weakObj1 doesn't have a retain count itself. This retain count will be one upon creation of the object, and it won't be deallocated until it's decreased to 0. In ARC, it still depends on the autoreleasepool to be deallocated. – Diego A. Rincon Jun 21 '13 at 07:28
  • You are right, but that sentence in the answer it misleading, perhaps you can change it. – Martin R Jun 21 '13 at 07:52
  • @DiegoArmandoRincon If you run the code posted in the question you will find that the instance of MyObj is never deallocated. The code exhibited the problem when compiled under ARC. The reason it isn't deallocated is because there is no autorelease pool present. objc_loadWeak, used by the ARC runtime, requires an autorelease pool. – Doug Richardson Jun 21 '13 at 15:32