cocoa - ¿Deben modelarse las relaciones "a-muchos" como propiedades?
key-value-observing key-value-coding (1)
Después de leer la Guía de programación de codificación de valores-clave , la Guía de programación de observación de valores-clave y la Guía de implementación de objetos modelo , así como leer muchas entradas de StackOverflow sobre el tema y experimentar con varios escenarios de modelado, siento que tengo una buena comprensión de cómo modelar mis datos
Termino usando las propiedades declaradas para todos mis atributos y las relaciones de uno, respaldados por ivars privados. Para los atributos de solo lectura que deben ser de escritura privada, utilizo el atributo de readonly
en la declaración de la interfaz .h
, luego readwrite
declarar la propiedad con el atributo readwrite
en una extensión de clase declarada en el archivo .m
. Dentro de los métodos de clase, siempre uso los descriptores de acceso de propiedad con la sintaxis de puntos y nunca accedo directamente a los archivos privados.
Sin embargo, hay un aspecto que todavía me deja perplejo: cómo modelar correctamente muchas relaciones, especialmente cuando la colección debe ser públicamente inmutable, pero privada mutable (es decir, los consumidores del objeto modelo no pueden agregar o eliminar objetos a la colección, pero el contenido de la colección es administrado privadamente por la clase).
Entiendo cómo implementar los métodos de acceso de KVC para muchas relaciones ( countOf<Key>
, objectsIn<Key>AtIndex
, etc.) y esta es la ruta que he estado siguiendo hasta ahora.
Sin embargo, he visto un ejemplo de código que usa las propiedades declaradas para exponer las relaciones, no implementa los métodos de acceso de KVC, pero todavía se observan valores-clave. Por ejemplo:
@interface MyModel : NSObject
{
// Note that the ivar is a mutable array,
// while the property is declared as an immutable array.
@private NSMutableArray *transactions_;
}
@property (nonatomic, retain, readonly) NSArray transactions;
@end
--------------------
@implementation MyModel
@synthesize transactions = transactions_;
- (void)privateMethodThatManagesTransactions
{
[[self mutableArrayValueForKey:@"transactions"] addObject:t];
}
@end
Si un objeto de consumo se agrega como observador de una instancia de MyModel
para la ruta de la clave "transactions"
, se notificará siempre que se agreguen o eliminen transactions
colección de transactions
(siempre que las mutaciones se realicen a través del método mutableArrayValueForKey:
).
Para mí, esta parece ser la forma más limpia de exponer muchas relaciones ya que no necesito codificar manualmente los accesos KVC de la colección y mantiene el código limpio.
Sin embargo, no parece ser la forma en que se promueve la documentación de Apple, y no puedo evitar preguntarme si el hecho de que funcione es solo un efecto secundario no confiable.
Entonces, antes de comprometerme con una u otra técnica en mis clases de modelo de la vida real para un proyecto en el que estoy empezando a trabajar, me gustaría obtener la opinión y el asesoramiento de experimentados desarrolladores de Cocoa.
Entonces, la pregunta es: si uso propiedades para modelar muchas relaciones, ¿todavía necesito implementar los métodos de acceso / mutador de KVC?
Actualizar
Incluso cuando declaro una propiedad de muchos como de readonly
, como en el ejemplo anterior, el código externo aún puede llamar a mutableArrayValueForKey:@"transactions"
en el objeto modelo y mutar la colección. Esto parece indicar que usar propiedades declaradas para muchas relaciones no es el camino a seguir, pero todavía siento que no lo entiendo ...
Sí.
Sin embargo, hay un aspecto que todavía me deja perplejo: cómo modelar correctamente muchas relaciones, especialmente cuando la colección debe ser públicamente inmutable, pero privada mutable ...
Fácil: declare la propiedad como readonly
de readonly
en el encabezado, luego redeclare como readwrite, copy
en una extensión de clase en el archivo de implementación.
Entiendo cómo implementar los métodos de acceso de KVC para muchas relaciones (
countOf<Key>
,objectsIn<Key>AtIndex
, etc.) y esta es la ruta que he estado siguiendo hasta ahora.
También hay mutantes. Con esto, no necesita usar mutableArrayValueForKey:
en su lugar, puede usar los accesos mutantes directamente. Seguirá recibiendo notificaciones de KVO, porque KVO ajusta esos métodos la primera vez que algo se agrega como observador de la propiedad.
Tengo una lista de los formatos de selector de acceso , incluidos los accesos mutantes, en mi blog.
Editar:
Incluso cuando declaro una propiedad de muchos como de solo lectura, como en el ejemplo anterior, el código externo aún puede llamar a
mutableArrayValueForKey:@"transactions"
en el objeto modelo y mutar la colección.
Esta es una buena razón para convertirlo en un hábito de usar los accesadores mutantes y evitar mutableArrayValueForKey:
No enviará mensajes de mutación desde fuera de la clase si obtiene una advertencia de compilación (no existe ese método [público]) cada vez que lo intente.
A pesar de la disponibilidad de mutableArrayValueForKey:
y el riesgo de que alguien lo use, las propiedades que cumplen con KVO son la manera de hacerlo.