2009-03-04 12 views
9

Quindi ho due oggetti, Fattura e InvoiceLineItem. InvoiceLineItem ha una proprietà denominata cost ed è creata dinamicamente in base ad altre proprietà. Per aiutare con il KVO/associazioni che uso:Impostazione di KVO per i valori calcolati, in base ai valori calcolati

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

Questo funziona benissimo. Quando modifico una proprietà come serivceCost, il costo principale nella vista tabella è aggiornato.

Nell'oggetto Fattura dispongo di un NSMutableArray di InvoiceLineItems. La fattura ha una proprietà simile denominata totalCost. Viene calcolato iterando sugli elementi pubblicitari e finché l'elemento pubblicitario non viene contrassegnato come eliminato (cosa che faccio per motivi di sincronizzazione), somma i costi e crea il totalCost.

Ora la mia domanda/problema. Come posso impostare TotalCost della fattura in modo che funzioni con KVO/binding quando uno dei costi dell'elemento pubblicitario è cambiato?

ho provato ad installare:

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

ma non funziona. Finisco con un errore nella console: [<NSCFArray 0x1499ff40> addObserver:forKeyPath:options:context:] is not supported. Key path: cost

risposta

6

Non ci credo: molte relazioni sono supportate per la propagazione automatica del KVO. La documentazione non dice esplicitamente in un modo o nell'altro, ma da quello che so di KVO in generale, osservare le sottochiavi di una relazione to-many tende ad essere non banale.

Il modo in cui si avvicinerebbe sarebbe quello di osservare manualmente la proprietà cost di ciascun oggetto InvoiceLineItem, implementando le funzioni di accesso KVC a-molti per la proprietà lineItems sulla classe Fattura facendo un/chiamata removeObserver addObserver nell'inserto/rimuovere metodi, rispettivamente, e quindi attivare manualmente la modifica totalCost utilizzando willChangeValueForKey:/didChangeValueForKey :. Quindi, qualcosa di simile (all'incirca codice abbozzato, disclaimer, ecc):

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

ero abbastanza vicino a questo tipo di implementazione me stesso ma è bello sentire è venuto da qualcun altro. Domanda però, l'impilamento di will/didChange ... perché non chiamare semplicementeChange? – zorn

+0

Penso che dovrebbe funzionare, se gli oggetti sottostanti lo implementano correttamente. Ad esempio, le Domande frequenti sui dati principali mostrano qualcosa di simile a questo: http://developer.apple.com/documentation/Cocoa/Conceptual/CoreData/Articles/cdFAQ.html#//apple_ref/doc/uid/TP40001802-SW3 –

+0

Con alcuni test iniziali questo funziona. Ho già avuto la maggior parte delle cose di osservazione sul posto (per annullare il supporto). Grazie ancora. – zorn

0

si potrebbe provare una soluzione più breve.

aggiungere al file di intestazione:

@property (retain, readonly) NSDecimalNumber *accountBalance; 

aggiungere al file di implementazione

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