Inicializando la propiedad Objective-C en la clase secundaria

Apple recomienda que acceda a las variables de instancia que respaldan sus propiedades directamente, en lugar de usar un getter/setter, al inicializar una clase:

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html

Sin embargo, parece que las variables de instancia que respaldan una propiedad en una clase principal no son accesibles en la clase secundaria; ¿Por qué es este el caso? Estoy extendiendo una clase en una biblioteca (Cocos2d) donde no todas las variables de instancia se inicializan en la función de inicio de la clase principal. Por ejemplo:

---

@interface parentClass

@property (assign) int myProperty;

----

@interface childClass : parentClass

----

@implementation childClass

- (id) init {
  // this doesn't work.
  _myProperty = 0;
}

preguntado el 10 de septiembre de 13 a las 01:09

@property tienen el prefijo de un guión bajo en las clases, supongo que deberías escribir _myProperty = 0; -

Es posible que no conozca el nombre de propiedad ivar utilizado en la implementación de la superclase. A continuación, puede inicializar con self.propertyname = -

Perdón por el tipo. De hecho, estoy usando _myProperty, pero eso tampoco funciona. -

2 Respuestas

No puede acceder a las variables de instancia de su superclase en una subclase, por lo que _variableName tampoco funcionará.

Usted init el método se verá algo como esto

- (instancetype)init {
    if (self=[super init]) {
        // subclass initialisation goes here
    }
}

Once [super init] devolvió un objeto, la parte de la superclase de su objeto se inicializa, por lo que debería ser seguro acceder a las propiedades utilizando sus captadores y definidores:

- (instancetype)init {
    if (self=[super init]) {
        self.superClassProperty = aValue;
    }
}

Echa un vistazo a "No enviar mensajes a sí mismo en Objective-C init" en QualityCoding sobre cuándo usar variables de instancia y cuándo llamar a métodos (por ejemplo, accesores de propiedad). En resumen: solo llame a métodos cuando su objeto esté en un estado consistente.

¿Por qué no puedes acceder a los ivares de respaldo?

Una declaración de propiedad en un encabezado declara un getter y setter para la propiedad, se crea un ivar de respaldo cuando se sintetiza la propiedad, lo que sucede en la implementación. (La síntesis automática y manual no hace la diferencia). Por lo tanto, la declaración de ivar solo es visible en la implementación. Si tiene que acceder absolutamente a ivars en subclases, debe hacerlos públicos (o semipúblicos colocándolos en un encabezado solo para subclases).

Respondido el 10 de Septiembre de 13 a las 02:09

Déjame aclarar. Parece que puedo acceder a variables de instancias en ciertos casos, como si en la implementación de la clase principal se sintetizara y respaldara explícitamente una propiedad (@synthesize myProperty = _myProperty). ¿Es eso correcto? - Peter

Gracias. Ahora entiendo el mensaje general de que solo debería usar getters y setters cuando el objeto está en un estado consistente. Sin embargo, estoy confundido acerca de por qué PUEDO (no debo) a veces acceder a las variables de instancia de un padre en una clase secundaria. Para darle un ejemplo de la biblioteca Cocos2d, la clase CCParticleMeteor en CCParticleExamples.m accede a la variable de instancia _startColor en el método initWithTotalParticles:, pero esa variable de instancia se declara en CCParticleSystem, que es el abuelo de esa clase. - Peter

_startColor se declara en el encabezado (CCParticleSystem.h) y luego se hace referencia en el @synthesize en la implementación (CCParticlesSystem.m). - Sebastián

Correcto. Pero eso rara vez (si no nunca) debería ser necesario. - Sebastián

¡Gracias por tu ayuda! Dos últimas preguntas: (1) Supongamos que hago una propiedad myProperty en mi encabezado y dejo que se sintetice automáticamente. Si también creo un ivar llamado _myProperty (sin sintetizar explícitamente), ¿myProperty estará respaldado por _myProperty? (2) En general, ¿cómo se hace público un ivar? - Peter

Puede hacer lo siguiente en su parentClass.h:

@interface parentClass {
  @protected
  int _myProperty;
}
@property (nonatomic) int myProperty;

Luego, en su childClass.m

- (instancetype)init {
    if (self=[super init]) {
        _myProperty = aValue;
    }
}

Los iVars se declaran como protegidos de forma predeterminada, por lo que sus hijos pueden verlos. No hay necesidad de escribir @protected. Y para tu información también puedes declararlos como @privado o @público.

Pero si escribe el iVar protegido en una interfaz privada en su parentClass.m, esto no funcionará y los niños no lo verán.

Respondido el 29 de enero de 16 a las 13:01

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.