2016-12-28 58 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運行或不運行,則可能是誤用了它。