¿Por qué debería llamar a self =

Digamos que creo mi clase y su método init . ¿Por qué debería llamar y devolver el valor de la superclase init asignada a sí mismo? ¿Qué casos cubre?

Agradecería ejemplos por qué lo necesitaría para la superclase Cocoa y para la que no es Cocoa.

¿Quieres decir por qué?

 self = [super init]; 

más bien que

 [super init]; 

Dos razones:

  1. en la inicialización, la falla se indica al devolver nil. Necesita saber si la inicialización del super objeto falló.
  2. la superclase podría elegir reemplazar el auto devuelto por + alloc con un objeto diferente. Esto es raro, pero ocurre con mayor frecuencia con los grupos de clases .

Editado en respuesta al comentario de Michael:

Puedo entender por qué necesito guardar y devolver [superinicio]. Pero, ¿es solo convencional y atractivo? ¿Nos usamos a nosotros mismos como una variable temporal para aprobar el resultado?

No. Se accede a las variables de instancia en relación con el puntero del self, por lo tanto, en lo siguiente:

 -(id) init { self = [super init]; if (self != nil) { myBoolIvar = YES; // The above is an implicit version of self->myBoolIvar = YES; } return self; } 

el yo claramente tiene que apuntar al bloque de memoria correcto, es decir, al que vas a devolver.

El otro punto es que si superinicial devuelve una instancia de clase diferente, entonces el rest del código después de esa línea puede no tener sentido, provocar fugas y fallas de memoria, ni siquiera hablar del objeto instanciado de esa clase.

Eso podría ser un problema. Si subclasé NSNumber y [superinicio] decidí devolver un NSString (que podría – no hay nada para detenerlo) que claramente sería un desastre. Cualquiera que sea el súper retorno de -init debe ser “compatible” con la subclase en el sentido de proporcionar espacio para ivars y ser más subclasible o es un error horrendo (a menos que, por supuesto, el problema esté documentado). Entonces, en general, no necesita preocuparse por verificar la clase. Sin embargo, lea la documentación. Véase, por ejemplo, la sección sobre la subclasificación de NSString en los documentos de NSString.

Sé que es un poco tarde para mi respuesta, pero no puedo evitar publicar un enlace que encontré muy útil para despejar mi duda sobre este problema.

Matt Gallagher: ¿Qué significa cuando asignas [superinicio] a ti mismo?

EDITAR: según los comentarios, aquí están los puntos esenciales en el enlace

Para entender por qué self=[super init]; debemos considerar muchos puntos. Vamos a abordarlo uno por uno.

Qué es el self

Cada método tiene dos parámetros ocultos: self y _cmd . Entonces la llamada al método

 - (id)initWithString:(NSString *)aString 

es cambiado por comstackdor en una llamada a función como esta

 id initWithString(id self, SEL _cmd, NSString *aString); 

¿Por qué nos necesitamos?

La realidad es que el comstackdor usa el parámetro self para resolver cualquier referencia a una variable de instancia dentro de un método.

Supongamos que tenemos un método setValueToZero y value es una variable de instancia de la clase a la que pertenece, luego la implementación

 - (void)setValueToZero { value = 0; } 

será convertido por el comstackdor en una función como esta

 void setValueToZero(id self, SEL _cmd) { self->value = 0; } 

¿El self ya tiene un valor cuando se llama init ?

A continuación se muestra un ejemplo de creación e inicialización típica de un objeto.

 [[MyClass alloc] initWithString:@"someString"] 

Aquí, cuando initWithString método initWithString , self tendrá el nuevo objeto asignado como su valor (es decir, el valor de retorno de [MyClass alloc] ). De hecho, está casi garantizado que es el valor final correcto.

Por qué self = [super init]; ?

Es porque [super init] está permitido hacer una de estas tres cosas:

  1. Devuelve su propio receptor (el self puntero no cambia) con valores de instancia heredados inicializados.
  2. Devuelve un objeto diferente con valores de instancia heredados inicializados.
  3. Devuelve nil , indicando falla.

En el primer caso, la asignación no tiene efecto sobre self . En el tercer caso, la inicialización ha fallado, self se establece en nil y se devuelve.

La razón detrás de la asignación a self es con el segundo caso. Considera lo siguiente

 - (id)initWithString:(NSString *)aString { self = [super init]; if (self) { instanceString = [aString retain]; } return self; } 

Queremos la conversión de

 instanceString = [aString retain]; 

a

 self->instanceString = [aString retain]; 

para actuar sobre el valor correcto y, por lo tanto, tenemos que cambiar el valor de self .

¿Cuándo devolvería [super init] un objeto diferente?

En una de las siguientes situaciones

  1. Objeto singleton (siempre devuelve el singleton en lugar de cualquier asignación posterior)
  2. Otros objetos únicos ( [NSNumber numberWithInteger:0] siempre devuelve el objeto global “cero”)
  3. Los clústeres de clases sustituyen las subclases privadas cuando inicializa una instancia de la superclase.
  4. Clases que eligen reasignar la misma clase (o compatible) basada en parámetros pasados ​​al inicializador.

En todos los casos menos en el final, continuar la inicialización del objeto devuelto si cambia es un error: el objeto devuelto ya está completamente inicializado y ya no es necesario para su clase. Entonces, un mejor enfoque de inicio será el siguiente

 - (id)initWithString:(NSString *)aString { id result = [super init]; if (self == result) { instanceString = [aString retain]; } return result; } 

Conclusión

No necesita asignar [super init] a self para que la mayoría de las clases funcionen. En algunos casos poco claros, en realidad es lo incorrecto.

Entonces, ¿por qué seguimos asignando a self ? Es la plantilla tradicional para un inicializador, y aunque en algunos casos está mal, es correcto en otros casos que se han escrito para esperar este enfoque.

Básicamente, cada clase de Objective-C es una subclase. Es una clase que has especificado o NSObject.

En la subclase (tu clase en la que estás trabajando) llamas a self = [super init]

Lo que hace básicamente es llamar al método init de la superclase (los que he mencionado anteriormente) (el constructor) y lo asigna a la clase actual.

Esto asegura que se llame al método de inicialización de las superclases.

Ahora para If (self) Esto básicamente verifica si el código anterior funcionó.

Esto se hace para asegurar que si llama a alguna Variable de instancia de la súper clase, podrá hacerlo.

En la mayoría de los casos, establecerse en [superinicio] no hace nada ya que [superinicio] terminará regresando a sí mismo de todos modos. Sin embargo, hay algunos casos excepcionales en los que [superinicio] devolverá algo diferente. Puede devolver nada si no puede inicializar la superclase por algún motivo o puede decidir devolver un objeto completamente diferente.

Fuente


Implementando el inicializador designado

**

yo

** Dentro de un método, self es una variable local implícita. No es necesario declararlo, y se configura automáticamente para que apunte al objeto al que se envió el mensaje. (Algo como esto en la progtwigción de Android.) Por lo general, se utiliza auto para que un objeto se pueda enviar un mensaje a sí mismo. Ejemplo aquí:

  return self; 

**

súper

** Cuando anulamos un método, queremos mantener qué método de la superclase está haciendo y hacer que su subclase agregue algo nuevo sobre eso. Para hacerlo más fácil, hay una directiva de comstackción en Objective-C llamada super. ¿Cómo funciona súper? Por lo general, cuando envía un mensaje a un objeto, la búsqueda de un método de ese nombre comienza en la clase del objeto. Si no existe tal método, la búsqueda continúa en la superclase del objeto. La búsqueda continuará en la jerarquía de herencia hasta que se encuentre un método adecuado. (Si llega a la parte superior de la jerarquía y no se encuentra ningún método, se lanza una excepción). Cuando enviamos un mensaje a super, estamos enviando un mensaje a self, pero la búsqueda del método omite la clase del objeto y comienza en la superclase. En el caso anterior, enviamos un mensaje de inicio a super. Esto llama al método init de NSObject.

Debido a que tiene que inicializar el objeto de alguna manera y, presumiblemente, desea realizar una inicialización, debe realizar una superclase, ya que está descendiendo de ella.