2012-08-17 11 views
6

unsere -init Methode Unter der Annahme, ruft nur die Nachrichten auf self, warum ist es üblich, Messaging zu überprüfen, ob self != nil wenn nil keine Wirkung hat?Warum check self! = Nil in -init wenn message nil keine Wirkung hat?

Lassen Sie uns sagen, dass wir einen Initialisierer haben wie folgt:

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

    return self; 
} 

Statt self zu prüfen, könnten wir schreiben:

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

    return self; 
} 

Nun, wenn aus irgendeinem Grund [super init] kehrt nil, gäbe es keinen Unterschied Soweit ich weiß, in dem Ergebnis der Methode. Warum führen wir diese Überprüfung ständig durch?

Antwort

7

Sie können eine Nachricht an nil senden, aber Sie können nicht auf die Instanzvariablen von nil zugreifen. Sie erhalten eine EXC_BAD_ACCESS Ausnahme.

Betrachten wir eine Klasse, die Instanzvariablen hat:

@implementation MyObject { 
    int instanceVariable; 
} 

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

Was passiert, wenn [super init] kehrt in diesem Beispiel gleich null? Sie werden versuchen, auf instanceVariable von einem Nullzeiger zuzugreifen, und Sie werden eine Ausnahme erhalten.

Auch wenn Sie nicht auf Instanzvariable zugreifen, können andere Dinge sicherlich schief gehen, wenn Sie nicht nach self == nil suchen. Sie können leicht malloc -allokierte Speicher- oder Dateizugriffsnummern auslassen oder sich an eine Methode übergeben, die keine NULL erwartet.

Andere Antworten behaupten, dass Sie Objekte verlieren können, wenn Sie nicht nach Null suchen. Zum Beispiel:

@implementation MyObject 

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

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

Dies wird nicht unter ARC auslaufen, auch wenn self Null ist. Bei der manuellen Referenzzählung (MRC) wird dieses Beispiel leak, unabhängig davon, ob self Null ist oder nicht, da es keinen Wert gibt, der die +1 Retain-Anzahl von [NSObject alloc] ausgleichen soll.

Der richtige Weg, es unter MRC zu tun, ist dies:

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

oder dies:

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

Keiner von denen, leckt, ob self Null ist oder nicht.

Wenn Sie die Setter-Methode umgehen, wie diese, werden Sie nur abstürzen, wenn self nil ist:

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

Es ist eher ein Signal - C hat keine Ausnahmen. –

+1

+1 obwohl, große Antwort. –

+0

Es ist eine CPU-Ausnahme, keine C++ - Ausnahme. Schau dir '/ usr/include/mach/exception_types.h' an. –

0

Wenn [super init] wiederum Rückkehr Null haben, dann würden Sie auf möglicherweise am Ende mehr Zuteilen Objekte, die nie benutzt werden, denn wenn du selbst zurückkehrst, wirst du null zurückgeben; Daher werden diese Objekte nicht freigegeben.

+0

Endlich hat @rob recht - das ist nicht der eigentliche Grund. –

+0

@ user1606088 Aber nicht entmutigen. Dies ist ein ziemlich subtiles Problem. –

Verwandte Themen