2009-03-04 29 views
9

Tengo dos objetos, Invoice y InvoiceLineItem. InvoiceLineItem tiene una propiedad llamada cost y se crea dinámicamente en función de otras propiedades. Para ayudar con el KVO/enlaces que uso:Configuración de KVO para valores calculados, según los valores calculados

+ (NSSet *)keyPathsForValuesAffectingCost { 
    return [NSSet setWithObjects:@"lineItemType", @"serviceCost", @"hourlyRate", @"timeInSeconds", @"productCost", @"quantityOfProduct", @"mileageCost", @"milesTraveled", nil]; 
} 

Esto funciona genial. Cuando edito una propiedad como serivceCost, el costo principal en la Vista de tabla se actualiza bien.

En el objeto Factura tengo un NSMutableArray de InvoiceLineItems. La factura tiene una propiedad similar llamada totalCost. Se calcula al iterar sobre las líneas de pedido y, siempre que la línea de pedido no esté marcada como eliminada (lo cual hago por razones de sincronización), se suman los costes y se crea el totalCost.

Ahora mi pregunta/problema. ¿Cómo configuro el Coste total de factura para que funcione con KVO/enlaces cuando ha cambiado uno de los costos de la línea de pedido?

I intentado fijar:

+ (NSSet *)keyPathsForValuesAffectingTotalCost { 
    return [NSSet setWithObjects:@"lineItems.cost", nil]; 
} 

pero no funciona. Termino con un error en la consola: [<NSCFArray 0x1499ff40> addObserver:forKeyPath:options:context:] is not supported. Key path: cost

Respuesta

6

No creo que se admitan muchas relaciones para la propagación automática de KVO. La documentación no dice explícitamente de una forma u otra, pero por lo que sé de KVO en general, la observación de subclaves de una relación a muchos tiende a ser no trivial.

La forma en que se acercaría a este sería observar manualmente la propiedad cost de cada objeto InvoiceLineItem, mediante la implementación de los descriptores de acceso KVC-a-muchos de los bienes lineItems en la clase Factura haciendo una llamada addObserver/removeObserver en la inserción/eliminar métodos, respectivamente, y luego desencadenar el cambio totalCost manualmente utilizando willChangeValueForKey:/didChangeValueForKey :. Así que algo como esto (código aproximadamente esbozado, descargos de responsabilidad, etc.):

- (void)insertObject:(InvoiceLineItem*)newItem inLineItemsAtIndex:(unsigned)index 
{ 
    [newItem addObserver:newItem forKeyPath:@"cost" options:0 context:kLineItemContext]; 
    [lineItems insertObject:newItem atIndex:index]; 
} 

- (void)removeObjectFromLineItemsAtIndex:(unsigned)index 
{ 
    [[lineItems objectAtIndex:index] removeObserver:self forKeyPath:@"cost"]; 
    [lineItems removeObjectAtIndex:index]; 
} 

- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context 
{ 
    if (context == kLineItemContext) 
    { 
     [self willChangeValueForKey:@"totalCost"]; 
     [self didChangeValueForKey:@"totalCost"]; 
    } 
} 
+0

estaba bastante cerca de este tipo de aplicación a mí mismo, pero es bueno escuchar que provienen de otra persona. Cuestión sin embargo, el apilamiento de will/didChange ... ¿por qué no simplemente llamar a didChange? – zorn

+0

Creo que debería funcionar, si los objetos subyacentes lo implementan correctamente. Por ejemplo, las Preguntas frecuentes sobre los datos centrales muestran algo como esto: http://developer.apple.com/documentation/Cocoa/Conceptual/CoreData/Articles/cdFAQ.html#//apple_ref/doc/uid/TP40001802-SW3 –

+0

Con algunas pruebas tempranas esto funciona. Ya tenía la mayoría de las cosas de observación en su lugar también (para el soporte de deshacer). Gracias de nuevo. – zorn

0

Puede intentar una solución más corta.

Añadir al archivo de encabezado:

@property (retain, readonly) NSDecimalNumber *accountBalance; 

Añadir al archivo de implementación

- (NSDecimalNumber *)totalCost 
{ 
    return [self valueForKeyPath:@"[email protected]"]; 
} 
Cuestiones relacionadas