2009-03-04 5 views
9

Ich habe also zwei Objekte, Invoice und InvoiceLineItem. InvoiceLineItem hat eine Eigenschaft namens cost und wird basierend auf anderen Eigenschaften dynamisch erstellt. Um mit den KVO/Bindings zu helfen benutze ich:Einrichten von KVO für berechnete Werte, basierend auf berechneten Werten

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

Das funktioniert super. Wenn ich eine Eigenschaft wie serivceCost bearbeite, werden die Hauptkosten in der Tabellenansicht aktualisiert.

Im Invoice-Objekt habe ich ein NSMutableArray von InvoiceLineItems. Rechnung hat eine ähnliche Eigenschaft mit dem Namen totalCost. Es wird durch Iteration über die Werbebuchungen berechnet, und solange die Werbebuchung nicht als gelöscht markiert ist (was ich aus Gründen der Synchronisierung tue), summiert sie die Kosten und erstellt die Gesamtkosten.

Jetzt meine Frage/Problem. Wie richte ich TotalCost für Invoice so ein, dass es mit KVO/Bindings funktioniert, wenn sich die Kosten einer Werbebuchung geändert haben?

Ich habe versucht, die Einrichtung:

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

aber es funktioniert nicht. Ich erhalte einen Fehler in der Konsole: [<NSCFArray 0x1499ff40> addObserver:forKeyPath:options:context:] is not supported. Key path: cost

Antwort

6

Ich glaube nicht, dass zu viele Beziehungen für automatische KVO-Propagation unterstützt werden. Die Dokumentation sagt nicht die eine oder die andere Erklärung, aber aus dem, was ich über KVO im Allgemeinen weiß, ist das Beobachten von Unterschlüsseln einer Zu-Viele-Beziehung tendenziell nicht trivial.

So wie ich dies manuell wäre nähern würde, um die cost Eigenschaft jedes InvoiceLineItem Objekt zu beobachten, indem Sie die zu viele KVC Accessoren für die lineItems Eigenschaft auf der Rechnungsklasse Implementierung eines addObserver/removeObserver Anruf im Einsatz zu tun/entfernen Methoden, und dann die totalCost Änderung manuell mit WillChangeValueForKey:/didChangeValueForKey: auslösen. So etwas in der Art (grob skizzierter Code, Disclaimer 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

ich ziemlich nah dran an dieser Art der Implementierung selbst war, aber es ist gut, es von jemand anderem kommen zu hören. Frage aber, das Stapeln von will/didChange ... warum rufst du nicht einfach didChange an? – zorn

+0

Ich denke, es sollte funktionieren, wenn die zugrunde liegenden Objekte es korrekt implementieren. Zum Beispiel zeigt die Core Data FAQ so etwas wie: http://developer.apple.com/documentation/Cocoa/Conceptual/CoreData/Articles/cdFAQ.html#//apple_ref/doc/uid/TP40001802-SW3 –

+0

Mit einigen frühen Tests funktioniert das. Ich hatte auch schon die meisten Beobachtungsdaten an Ort und Stelle (um Unterstützung rückgängig zu machen). Danke noch einmal. – zorn

0

Sie könnten eine kürzere Lösung versuchen.

in die Header-Datei hinzufügen:

@property (retain, readonly) NSDecimalNumber *accountBalance; 

in die Datei Implementierung hinzufügen

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