2012-08-17 14 views
6

Suponiendo que nuestro método -init solo invoca mensajes en self, ¿por qué es común comprobar si self != nil si el mensaje nil no tiene ningún efecto?¿Por qué verificar self! = Nil in -init cuando el envío de mensajes nulo no tiene ningún efecto?

Digamos que tenemos un inicializador de la siguiente manera:

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

    return self; 
} 

En lugar de comprobar self, podríamos escribir:

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

    return self; 
} 

Ahora bien, si por alguna razón [super init] vuelve nil, no habría ninguna diferencia en el resultado del método hasta donde yo sé. ¿Por qué entonces constantemente realizamos este control?

Respuesta

7

Puede enviar un mensaje a cero, pero no puede acceder a las variables de instancia de nil. Obtendrá una excepción EXC_BAD_ACCESS.

Considérese una clase que tiene variables de instancia:

@implementation MyObject { 
    int instanceVariable; 
} 

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

¿Qué pasa si [super init] devuelve nil en este ejemplo? Intentará acceder al instanceVariable desde un puntero nulo y obtendrá una excepción.

Incluso si no está accediendo a ninguna variable de instancia, otras cosas ciertamente pueden salir mal si no marca self == nil. Puede filtrar fácilmente malloc -la memoria asignada o los identificadores de archivos, o pasar a un método que no espera nada.

Otras respuestas afirman que puede filtrar objetos si no busca cero. Por ejemplo:

@implementation MyObject 

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

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

Esto no se escape bajo ARC, incluso si self es nula. En el recuento de referencia manual (MRC), este ejemplo tendrá una fuga si self es nulo o no, porque no hay nada para equilibrar el recuento de retenciones +1 de [NSObject alloc].

La forma correcta de hacerlo bajo MRC es la siguiente:

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

o esto:

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

Ninguno de los que se escape, ya sea self es nula o no.

Si se omite el método de selección, de esta manera, usted acaba de bloquearse si self es nula:

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

Es más bien una señal: C no tiene excepciones. –

+1

+1 sin embargo, excelente respuesta. –

+0

Es una excepción de CPU, no una excepción de C++. Echa un vistazo a '/ usr/include/mach/exception_types.h'. –

0

Si [súper init] hizo en nulo de retorno a su vez, entonces terminaría posiblemente la asignación de más objetos que nunca serán utilizados, ya que cuando regreses a ti mismo, regresarás nulo; Entonces esos objetos no serán lanzados.

+0

Entonces, finalmente, @rob tiene razón: esta no es la razón real. –

+0

@ user1606088 No se desanime. Este es un problema bastante sutil. –

Cuestiones relacionadas