2016-12-28 61 views
2

下面是使用ARC的OS X的Objective-C程序 - 您可以使用cc -fobjc-arc -o objc_arc_test objc_arc_test.m或其他东西来构建它。它创建两对两个对象,一个使用alloc/init,另一个使用工厂函数(在ARC代码中使用autorelease),所有autorelease池之外,都会打印init和dealloc消息去。为什么这些ARC对象的行为不一致?

#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(); 
} 

我预料得到的init消息4个对象和dealloc的消息2,因为ARC将确保ALLOC + init'd对象被销毁,并在帐户缺乏自动释放池,将单独留下其他人。

但我得到的却是4个初始化对象的消息,并dealloc的消息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 

我不明白这种行为!我期望值= 5和值= 7对象表现相同。

它为什么这样做?

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

回答

4

因为我相信OS X 10.9,出现在顶层自动创建一个自动释放池,即使你不做一个(这摆脱了历史性的“没有自动释放池自动释放的对象,只是泄漏”警告)。

这就是说,这与这种情况并不特别相关。 ARC不承诺任何东西都会被自动释放。当它可以证明你以后不会使用该对象时,可以使用显式发布。 ARC仅有义务确保具有强引用的对象不被销毁,并且没有强引用的对象被销毁。 Autoreleasepool是ARC可自由使用或不使用的实现细节。作为优化,ARC往往会避免在过去我们手动使用它的地方使用自动释放池。

值得注意的是,dealloc从未实际承诺过。程序可以自由终止而不运行它(这是一个巨大的优化,这就是为什么ObjC程序可以比C++程序更快地终止)。在这种情况下,它会发生,但如果您依靠dealloc运行或不运行,则可能是误用了它。