2009-06-03 17 views
7

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 ...

+0

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: .. –

Respuesta

6

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: Declarar la propiedad como readonly en la cabecera, a continuación, redeclare it as readwrite, copy in a class extension en el archivo de implementación.

entiendo cómo poner en práctica los métodos de acceso para las relaciones KVC-a-muchos (countOf<Key>, objectsIn<Key>AtIndex, etc.) y esta es la ruta que he estado siguiendo hasta ahora.

También hay mutantes. Con estos, 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 a list of the accessor selector formats, incluidos los accesos mutantes, en mi blog.

Editar:

Incluso cuando declaro una propiedad de sólo lectura a todos los que, 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.

Esta es una buena razón para que sea un hábito 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 el camino a seguir aquí.

+0

Gracias por la respuesta rápida. He editado mi pregunta para que sea más precisa: si utilizo propiedades para modelar muchas relaciones, ¿todavía necesito implementar los métodos de acceso/mutador de KVC? –

+0

Sí. Puedes sintetizar el getter, pero el setter se equivocará si quieres un objeto mutable en tu ivar (@property (copy) te da * copias * inmutables), y @synthesize no te dará ninguno de los accessors precisos (como objectIn AtIndex :). Por lo tanto, aún necesita implementar * al menos * el colocador usted mismo. –

+0

Todavía estoy confundido ... Si necesito implementar los métodos de KVC (accesadores y mutadores), ¿cuál es el valor agregado de declarar una propiedad encima de ellos? –

Cuestiones relacionadas