Después de leer el valor-clave Guía de codificación de programación, la valor-clave Observando Guía de programación y la Modelo guía de implementación de objetos, así como la lectura de muchas entradas StackOverflow sobre el tema y experimentar con diferentes escenarios de modelado, lo Siento que tengo una buena idea de cómo modelar mis datos.¿Deben modelarse las relaciones "to-many" como propiedades?
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 poder escribirse de manera privada, utilizo el atributo readonly
en la declaración de interfaz .h
, luego vuelvo a 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 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 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 seguido hasta ahora.
Sin embargo, he visto algunos ejemplos de código que usan las propiedades declaradas para exponer las relaciones, no implementan los métodos de acceso de KVC, pero aún 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 añade a sí mismo como un observador de una instancia de MyModel
para la ruta de la clave "transactions"
, será notificado cada vez que se añaden o eliminan las transacciones de la colección transactions
(siempre que las mutaciones son hecho a través del método mutableArrayValueForKey:
).
Para mí, esta parece ser la manera más limpia de exponer a muchas relaciones ya que no necesito codificar manualmente los accesos de 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.
Así que 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?
actualización
Incluso cuando declarar una propiedad a muchos como readonly
, al igual que en el ejemplo anterior, el código externo aún puede llamar mutableArrayValueForKey:@"transactions"
en el objeto de modelo y mutar la colección. Esto parece indicar que el uso de propiedades declaradas para muchas relaciones no es el camino a seguir, pero todavía siento que no lo entiendo ...
Me acabo de dar cuenta de que incluso para propiedades simples que representan atributos o relaciones de uno, declarar la propiedad como de solo lectura en el .H y volver a declarar como readwrite en .M permite que el código externo cambie el valor de propiedad mediante el uso de KVC setValue: forKey: ... Parece que KVC permite omitir la semántica expresada en la declaración de propiedad en todos los casos, así que supongo que no debería sorprenderme que pueda mutar una colección de solo lectura usando mutableArrayValueForKey: .. –