2012-08-17 77 views
6

假設我們的-init方法僅調用self上的消息,爲什麼通常要檢查消息nil是否不起作用self != nil爲什麼在消息nil無效時檢查self!= nil in -init?

比方說,我們有一個初始化如下:

- (id)init 
{ 
    self = [super init]; 
    if (self) { 
     [self doThis]; 
     [self setFoo:@"Bar"]; 
    } 

    return self; 
} 

而不是檢查self,我們可以這樣寫:

- (id)init 
{ 
    self = [super init]; 
    [self doThis]; 
    [self setFoo:@"Bar"]; 

    return self; 
} 

現在,如果由於某種原因[super init]回報nil,不會有什麼區別在我所知的方法的結果中。爲什麼我們會不斷地執行這項檢查?

回答

7

您可以發送消息給nil,但不能訪問nil的實例變量。你會得到一個EXC_BAD_ACCESS例外。

考慮一個實例變量的類:

@implementation MyObject { 
    int instanceVariable; 
} 

- (id)init { 
    self = [super init]; 
    instanceVariable = 7; 
    return self; 
} 

如果[super init]回報在這個例子中無會發生什麼?您將嘗試從空指針訪問instanceVariable,您將得到一個異常。

即使你沒有訪問任何實例變量,其他的事情可以肯定出問題,如果你不檢查self == nil。你可以很容易地泄漏malloc-分配的內存或文件句柄,或者將自己傳遞給一些不期望爲零的方法。

其他答案聲稱,如果你不檢查零,你可以泄漏對象。例如:

@implementation MyObject 

@synthesize someProperty; // assume it's an NSObject * 

- (id)init { 
    self = [super init]; 
    [self setSomeProperty:[[NSObject alloc] init]]; 
    return self; 
} 

這不會在ARC下泄漏,即使self爲零。在手動引用計數(MRC),這個例子將泄漏self是否是零或沒有,因爲沒有什麼平衡+1從[NSObject alloc]保留計數。

正確的方式做到這一點MRC下是這樣的:

- (id)init { 
    self = [super init]; 
    [self setSomeProperty:[[[NSObject alloc] init] autorelease]]; 
} 

或本:

- (id)init { 
    self = [super init]; 
    NSObject *object = [[NSObject alloc] init]; 
    [self setSomeProperty:object]; 
    [object release]; 
    return self; 
} 

這些都不會有泄漏,self是否爲零與否。

如果繞過setter方法,這樣,你只會崩潰,如果self是零:

- (id)init { 
    self = [super init]; 
    _someProperty = [[NSObject alloc] init]; 
    return self; 
} 
+0

這是相當的信號 - C沒有異常。 – 2012-08-17 07:24:09

+1

+1雖然,很好的答案。 – 2012-08-17 07:27:39

+0

這是一個CPU異常,而不是C++異常。查看'/ usr/include/mach/exception_types.h'。 – 2012-08-17 07:29:18

0

如果[超級初始化]又回零做到了,那麼你最終將有可能分配更多永遠不會使用的對象,因爲當你返回自己的時候,你將返回零;所以這些對象不會被釋放。

+0

最後@rob是對的 - 這不是真正的原因。 – 2012-08-17 07:27:24

+0

@ user1606088雖然不要氣餒。這是一個非常微妙的問題。 – 2012-08-17 07:38:35

相關問題