¿Por qué no debería usar los accesos de Objective C 2.0 en init / dealloc?

En la respuesta de @mmalc a esta pregunta , afirma que “en general, no debe usar métodos de acceso en dealloc (o init)”. ¿Por qué Mmalc dice esto?

Las únicas razones reales que se me ocurren son el rendimiento y evitar los efectos secundarios desconocidos de los setters @dynamic.

¿Discusión?

Se trata de usar un código idiomáticamente consistente. Si configura correctamente todo su código, existen conjuntos de reglas que garantizan que el uso de un descriptor de acceso en init / dealloc sea seguro.

El gran problema es que (como dijo mmalc) el código que establece el estado predeterminado de las propiedades no debe ir a través de un descriptor de acceso porque conduce a todo tipo de problemas desagradables. La trampa es que no hay ninguna razón para que init tenga que configurar el estado predeterminado de una propiedad. Por una serie de razones, me he estado moviendo a los usuarios que se inicializan, como en el ejemplo simple a continuación:

- (NSMutableDictionary *) myMutableDict { if (!myMutableDict) { myMutableDict = [[NSMutableDictionary alloc] init]; } return myMutableDict; } 

Este estilo de inicialización de propiedad permite diferir una gran cantidad de código de inicio que en realidad puede no ser necesario. En el caso anterior, init no es responsable de ingresar el estado de las propiedades, y es completamente seguro (incluso necesario) que uno use los accesadores en el método init.

Es cierto que esto impone restricciones adicionales en su código, por ejemplo, las subclases con accesodores personalizados para una propiedad en la superclase deben llamar al acceso de superclases, pero esas restricciones no están fuera de línea con otras restricciones comunes en Cocoa.

Básicamente es una guía para minimizar el potencial de errores.

En este caso, existe la (posibilidad) de que su setter / getter pueda hacer inadvertidamente suposiciones directas o indirectas sobre el estado del objeto. Estas suposiciones podrían ser un problema cuando el objeto está en el medio de ser configurado o destruido.

Por ejemplo, en el código siguiente, el observador no sabe que ‘Ejemplo’ está siendo destruido y podría suponer que otras propiedades, que ya han sido liberadas, son válidas.

(Podría argumentar que su objeto debería eliminar a todos los observadores antes de cortarse, lo cual sería una buena práctica, y otra guía para evitar problemas inadvertidos).

 @implementation Example -(void) setFoo:(Foo*)foo { _foo = foo; [_observer onPropertyChange:self object:foo]; } -(void) dealloc { ... self.foo = nil; } @end 

Ha respondido a su propia pregunta:

  1. El rendimiento puede ser una razón perfectamente adecuada en sí misma (especialmente si sus accesadores son atómicos).
  2. Debe evitar cualquier efecto secundario que puedan tener los usuarios de acceso.

Esto último es particularmente un problema si su clase puede ser subclasificada.

Sin embargo, no está claro por qué esto se aborda específicamente en los accesadores Objective-C 2 . Se aplican los mismos principios, ya sea que use propiedades declaradas o que escriba accesadores.

Puede ser que el colocador tenga una lógica que deba ejecutarse o tal vez la implementación use un ivar con un nombre diferente del getter / setter o quizás dos ivars que necesiten ser liberados y / o tengan su valor establecido en nil. La única forma segura es llamar al colocador. Es responsabilidad del colocador escribir de tal manera que no se produzcan efectos secundarios indeseables cuando se invoca durante init o dealloc.

De “Cocoa Design Patterns”, Buck, Yacktman, pp. 115: “… no hay una alternativa práctica al uso de accesoantes cuando se utilizan variables de instancia sintetizadas con el moderno Objective-C runtime o …”

De hecho, para una clase que viene y se va con bastante frecuencia (como un controlador de vista de detalles), quiere usar el acceso en init; de lo contrario, podría terminar liberando un valor en viewDidUnload al que intenta acceder más tarde (lo muestran en CS193P …)

Puede crear los mismos problemas al NO llamar al colocador al asignar / desasignar.

No creo que pueda lograr nada mediante el uso de retener / liberar directamente en init / dealloc. Usted acaba de cambiar el conjunto de posibles errores.

Cada vez que tiene que pensar en el orden de asignación de propiedad / desasignación.