Cuál es la diferencia entre ivars y propiedades en Objective-C

¿Cuál es la diferencia semántica entre estas 3 formas de usar ivars y propiedades en objective-c?

1.

@class MyOtherObject; @interface MyObject { } @property (nonatomic, retain) MyOtherObject *otherObj; 

2.

 #import "MyOtherObject.h" @interface MyObject { MyOtherObject *otherObj; } @property (nonatomic, retain) MyOtherObject *otherObj; 

3.

  #import "MyOtherObject.h" @interface MyObject { MyOtherObject *otherObj; } 

El número 1 difiere de los otros dos al declarar hacia adelante la clase MyOtherObject para minimizar la cantidad de código visto por el comstackdor y el enlazador y también potencialmente evitar las referencias circulares. Si lo hace de esta manera, recuerde poner el #import en el archivo .m.

Al declarar un @property, (y coincidir con @synthesize en el archivo .m), se generan automáticamente métodos de acceso con la semántica de la memoria manejada como se especifica. La regla de oro para la mayoría de los objetos es Conservar, pero NSStrings, por ejemplo, debe usar Copiar. Mientras que Singletons y Delegados usualmente deben usar Asignar. Los accesadores de escritura a mano son tediosos y propensos a errores, por lo que se ahorran muchos errores de tipeo y de escritura.

Además, declarar una propiedad sintetizada le permite llamar a un método de acceso usando notación de puntos como esta:

 self.otherObj = someOtherNewObject; // set it MyOtherObject *thingee = self.otherObj; // get it 

En lugar de la forma normal de pasar mensajes:

 [self setOtherObject:someOtherNewObject]; // set it MyOtherObject *thingee = [self otherObj]; // get it 

Detrás de las escenas realmente estás llamando a un método que se ve así:

 - (void) setOtherObj:(MyOtherObject *)anOtherObject { if (otherObject == anOtherObject) { return; } MyOtherObject *oldOtherObject = otherObject; // keep a reference to the old value for a second otherObject = [anOtherObject retain]; // put the new value in [oldOtherObject release]; // let go of the old object } // set it 

…o esto

 - (MyOtherObject *) otherObject { return otherObject; } // get it 

Dolor total en el trasero, a la derecha. Ahora hazlo por cada ivar en la clase. Si no lo haces exactamente bien, obtienes una pérdida de memoria. Lo mejor es dejar que el comstackdor haga el trabajo.

Veo que el Número 1 no tiene un ivar. Suponiendo que no se trata de un error tipográfico, está bien porque las directivas @property / @synthesize también declararán un ivar por detrás de las escenas. Creo que esto es nuevo para Mac OS X: Snow Leopard e iOS4.

El número 3 no tiene esos accesores generados, por lo que debe escribirlos usted mismo. Si desea que sus métodos de acceso tengan efectos secundarios, realice su baile estándar de administración de memoria, como se muestra arriba, luego haga el trabajo adicional que necesite, dentro del método de acceso. Si sintetizas una propiedad y escribes la tuya , entonces tu versión tiene prioridad.

¿Cubrí todo?

En los viejos tiempos tenías ivars, y si querías dejar que otras clases los configuraran o los leyeras, entonces tenías que definir un getter (es decir, -(NSString *)foo) y un setter (es decir, -(void)setFoo:(NSString *)aFoo; ).

Lo que te dan las propiedades es setter y getter gratis (¡casi!) Junto con un ivar. Entonces, cuando defines una propiedad ahora, puedes establecer la atomicidad (por ejemplo, ¿quieres permitir múltiples acciones de configuración de varios hilos), así como asignar / retener / copiar semántica (es decir, si el colocador copia el nuevo valor? o simplemente guarde el valor actual, importante si otra clase intenta establecer su propiedad de cadena con una cadena mutable que podría cambiarse más adelante).

Esto es lo que hace @synthesize . Muchas personas dejan el mismo nombre, pero puedes cambiarlo cuando escribes tu statement de sintetizar (es decir, @synthesize foo=_foo; significa hacer un ivar llamado _foo para la propiedad foo , así que si quieres leer o escribir esta propiedad) y no usa self.foo , tendrá que usar _foo = ... – solo le ayuda a capturar referencias directas al ivar si solo quiere ir a través del setter y getter).

A partir de Xcode 4.6, no es necesario utilizar la instrucción @synthesize ; el comstackdor lo hará automáticamente y, de forma predeterminada, antepondrá el nombre de ivar a _ .