Question: Why do these ARC objects behave inconsistently?

Question

Why do these ARC objects behave inconsistently?

Answers 1
Added at 2016-12-28 19:12
Tags
Question

Here's an Objective-C program for OS X that uses ARC - you can build it with cc -fobjc-arc -o objc_arc_test objc_arc_test.m or something. It creates two pairs of two objects, one using alloc/init and one using a factory function (the sort of thing you'd use autorelease for in pre-ARC code), all outside any autorelease pool, printing init and dealloc messages as it goes.

#import <Foundation/NSObject.h>
#include <stdio.h>

#if !__has_feature(objc_arc)
#error
#endif

@interface TestClass:NSObject {
    int value;
}
-(TestClass *)initWithValue:(int)value;
-(void)dealloc;
+(TestClass *)testClassWithValue:(int)value;
@end

@implementation TestClass
-(TestClass *)initWithValue:(int)value_ {
    if((self=[super init]))
        self->value=value_;

    printf("init: self=%p value=%d\n",self,self->value);
    return self;
}

-(void)dealloc {
    printf("dealloc: self=%p value=%d\n",self,self->value);
}

+(TestClass *)testClassWithValue:(int)value {
    return [[TestClass alloc] initWithValue:value];
}

@end

static void f() {
    TestClass *c5=[TestClass testClassWithValue:5];
    TestClass *c6=[[TestClass alloc] initWithValue:6];
}

static void f2() {
    TestClass *c7=[TestClass testClassWithValue:7];
    TestClass *c8=[[TestClass alloc] initWithValue:8];
}

int main() {
    f();
    f2();
}

I'd expected to get init messages for 4 objects, and dealloc messages for 2, since ARC will ensure the alloc+init'd objects are destroyed and, on account of the lack of autorelease pool, will leave the other ones alone.

But what I get instead is init messages for 4 objects, and dealloc messages for 3:

init: self=0x7fea20500690 value=5
init: self=0x7fea205006f0 value=6
dealloc: self=0x7fea205006f0 value=6
init: self=0x7fea205006f0 value=7
init: self=0x7fea20500700 value=8
dealloc: self=0x7fea20500700 value=8
dealloc: self=0x7fea205006f0 value=7

I don't understand this behaviour! I'd expect the value=5 and value=7 objects to behave the same.

Why is it doing this?

(OS X 10.11.6; Xcode 8 - Apple LLVM version 8.0.0 (clang-800.0.38), Target: x86_64-apple-darwin15.6.0, Thread model: posix)

Answers
nr: #1 dodano: 2016-12-28 20:12

Since I believe OS X 10.9, there is an autorelease pool automatically created at the top level, even if you don't make one (this got rid of the historic "object autoreleased without an autorelease pool, just leaking" warning).

That said, that's not particularly relevant to this situation. ARC doesn't promise that anything will ever be autoreleased. It's free to use explicit releases when it can prove you won't use the object later. ARC is only obligated to ensure that objects with strong references are not destroyed, and that objects with no strong references are destroyed. Autoreleasepool is an implementation detail that ARC is free to use or not use at its discretion. As an optimization, ARC often avoids the autorelease pool in places that we would have used it manually in the past.

It's worth also noting that dealloc is never actually promised. The program is free to terminate without running it (this is a massive optimization which is why ObjC programs can terminate dramatically faster than C++ programs). In this case it happens to, but if you're relying on dealloc to run or not run, you're probably misusing it.

Source Show
◀ Wstecz