objective-c ios properties instance-variables

objective c - ¿Debe cada ivar ser una propiedad?



objective-c ios (4)

Veo que se recomienda en todas partes al codificar para iOS que las propiedades se utilicen para acceder a variables de instancia debido a los beneficios que esto otorga a la gestión de memoria, entre otras cosas.

Este consejo no me sienta terriblemente bien. Encuentro que el uso de propiedades en lugar de ivars simples simplemente requiere demasiado código y realmente no veo los beneficios si te sientes cómodo con la administración de la memoria. ¿Es realmente tan importante? ¿Cuál es su enfoque para gestionar variables de instancia?


Las propiedades son solo azúcares sintácticos que evitan que escribas los mismos métodos una y otra vez. Con una propiedad tienes un colocador que libera el objeto viejo y conserva el nuevo gratis.


No es realmente necesario declarar propiedades para todos los ivars. Algunos puntos vienen a la mente:

  • Si un ivar solo se va a asignar a una vez durante la vigencia del objeto, no se gana nada declarando una propiedad. Solo retenga / copie / asigne durante init y luego suéltelo según sea necesario durante dealloc .
  • Si se va a cambiar un ivar con frecuencia, declarar una propiedad y usar siempre los accessors hará que sea más fácil evitar los errores de administración de memoria.
  • Puede declarar propiedades en una extensión de clase en el archivo .m en lugar del archivo .h si las propiedades y ivars están destinados a ser privados.
  • Cuando apunte a iOS 4.0+, no necesita declarar ivars en absoluto en su encabezado si define una propiedad y sintetiza accesos.

Por lo tanto, generalmente uso propiedades, pero para cosas como un NSMutableArray que un objeto asigna durante init y usa para contener un montón de whatevers, usaré un ivar simple dado que nunca voy a reasignar el ivar.


Para los campos privados, sugiero que es seguro usar ivars directos solo para tipos primitivos (BOOL / int / float, etc.). Encuentro una buena práctica que engloba todo lo relacionado con la gestión de la memoria en propiedades, incluso campos raramente utilizados. Una ventaja adicional de este enfoque es que IDE usualmente resalta el acceso directo de ivars de manera diferente, por lo que siempre tendrá una buena separación de campos escalares simples y campos de tipo de objeto.

Contrario a esto, desalentaría fuertemente cualquier ivars directo en la interfaz pública de la clase . Debido a la naturaleza dinámica del lenguaje, puede generar errores de tiempo de ejecución que son extremadamente difíciles de encontrar, localizar y corregir. Considere la siguiente jerarquía

@interface BaseControl ... @end @interface Label : BaseControl ... @end @interface Button : BaseControl { @public BOOL enabled; } @end

y un fragmento de código

- (void)enableAllButtons { NSArray *buttons = [self getAllButtons]; // expected to contain only Button instances for (Button *button in buttons) { button->enabled = YES; } }

Ahora imagina que hay un error en alguna parte de la lógica -getAllButtons y también obtienes algunas etiquetas devueltas en esa matriz, por lo que esas instancias de la clase Label no se asignarán. El hecho que puede ser sorprendente es que -enableAllButtons no fallará en ese caso. Pero en ese momento, la estructura interna de las instancias de Label está dañada y esto causará un comportamiento indefinido y bloqueos cuando se utilizan en otro lugar.

Al igual que algunos problemas populares con la administración de memoria (y en general, con punteros colgantes), este tipo de problemas es difícil de encontrar y localizar porque la apariencia del error generalmente es distante (en términos de tiempo, código o flujo de aplicaciones) del colocar, causando el error. Pero con ese problema en particular, incluso no tiene herramientas prácticas (como analizadores de fuga / zombies, etc.) que lo ayuden a localizarlo y solucionarlo, incluso cuando aprende cómo reproducirlo y puede investigar fácilmente un estado erróneo.

Obviamente, si usa @property (assign) BOOL enabled; Obtendrá una excepción de tiempo de ejecución fácil de diagnosticar y corregir en -enableAllButtons.


Si bien la respuesta de Daniel es correcta, creo que se pierde un punto importante. A saber:

Encuentro que el uso de propiedades en lugar de ivars simples simplemente requiere demasiado código y realmente no veo los beneficios si te sientes cómodo con la administración de la memoria.

Los beneficios son consistencia; manejo de memoria consistente y comportamiento consistente.

Notablemente, estas dos líneas de código en realidad pueden tener un comportamiento extremadamente diferente en tiempo de ejecución:

iVar = [foo retain]; self.iVar = foo;

El primero es una configuración directa de la variable de instancia y no habrá notificaciones de cambio. El segundo pasa por el colocador y, por lo tanto, conserva las personalizaciones de las subclases en el conjunto y garantiza que cualquier observador de la propiedad reciba notificación del cambio .

Si usa ivars directamente a lo largo de su código (internamente para la clase, si usa ivars de una instancia directamente desde fuera de esa instancia, bueno ... cualquier contratista que trabaje en su base de código debe duplicar sus tasas;), entonces debe también maneja la propagación de la notificación de cambio de forma manual (normalmente llamando a willChangeValueForKey: / didChangeValueForKey ) o modifica explícitamente su aplicación para evitar el uso de mecanismos que se basan en la observación de clave-valor.

Usted dice "toma demasiado código". No veo eso; en las dos líneas de código anteriores, la sintaxis de puntos tiene menos caracteres. Incluso llamar al método setter usando la sintaxis tradicional sería menos código.

Y no descarte el valor de centralizar la administración de memoria; una omisión accidental en una miríada de sitios de llamadas y crash city.