iHunter
iHunter

Reputation: 6205

Objective-C associated objects leaking under ARC

I have encountered with a strange objc_setAssociatedObject behavior under ARC. Consider the following code:

static char ASSOC_KEY;

@interface DeallocTester : NSObject
@end

@implementation DeallocTester
- (void) dealloc
{
    NSLog(@"DeallocTester deallocated");
    //objc_setAssociatedObject(self, &ASSOC_KEY, nil, OBJC_ASSOCIATION_RETAIN);
}
@end

@implementation AppDelegate
- (void) applicationDidFinishLaunching:(UIApplication *)application
{
    NSObject *test = [[DeallocTester alloc] init];
    objc_setAssociatedObject(test, &ASSOC_KEY, [[DeallocTester alloc] init],
                             OBJC_ASSOCIATION_RETAIN);
}

I'm creating an instance of DeallocTester, then I set another DeallocTester as an associated object for it, then both of them go out of scope.

I expect the -dealloc of the first object to be called, then the associated object to be deallocated too, but I see the "DeallocTester deallocated" message printed only once. If I uncomment the objc_setAssociatedObject line in -dealloc, the second object gets deallocated too.

The Objective-C reference states that associated objects are deallocated automatically upon object destruction. Is it a compiler/ARC/whatever issue or am I missing something?

Update

This sample code is actually working if you run it from a brand-new project. But I have two ARC-enabled projects where it doesn't. I'll do some investigation and provide a better sample.

Update 2

I've filled a rdar://10636309, Associated objects leaking if NSZombie objects enabled in ARC-enabled project

Upvotes: 9

Views: 4988

Answers (2)

iHunter
iHunter

Reputation: 6205

I've found a source of a problem - I had NSZombie objects enabled in both my projects where this bug appears.

As far as I understand, when zombie objects are enabled, the normal instances are replaced with NSZombie upon deallocation, but all the associated objects are left alive! Beware of that behavior!

I've created a rdar://10636309

Update: There's a workaround by Cédric Luthi, and this issue appears to be fixed in iOS 6.

Upvotes: 9

jlehr
jlehr

Reputation: 15597

The code you posted works exactly as advertised under ARC. I rewrote your dealloc implementation to help make things a little more obvious.

- (void)dealloc
{
    NSLog(@"deallocating %@", self);
}

Here's the resulting log:

2012-01-03 06:49:39.754 ARC  Stuff[47819:10103] deallocating <DeallocTester: 0x6878800>
2012-01-03 06:49:39.756 ARC  Stuff[47819:10103] deallocating <DeallocTester: 0x688b630>

Are you sure you're compiling with ARC enabled?

Upvotes: 1

Related Questions