Einrichten KVO für berechneten Werte, basierend auf berechneten Werten
-
03-07-2019 - |
Frage
Also ich habe zwei Objekte, Rechnung und InvoiceLineItem. InvoiceLineItem hat eine Eigenschaft namens cost
und dynamisch auf andere Eigenschaften basierend erstellt. Um mit der KVO / Bindungen Ich benutze:
+ (NSSet *)keyPathsForValuesAffectingCost {
return [NSSet setWithObjects:@"lineItemType", @"serviceCost", @"hourlyRate", @"timeInSeconds", @"productCost", @"quantityOfProduct", @"mileageCost", @"milesTraveled", nil];
}
Dies funktioniert gut. Wenn ich eine Eigenschaft wie serivceCost die Hauptkosten in der Tabellenansicht bearbeiten aktualisiert Ordnung.
Im Rechnungs Objekt habe ich eine NSMutableArray von InvoiceLineItems. Rechnung hat eine ähnliche Eigenschaft namens totalCost
. Es wird durch Iterieren über die Positionen berechnet und solange die Position nicht als gelöscht markiert ist (was ich für die Synchronisierung Gründen tun) es die Kosten addiert und schafft die Totalcost.
Nun meine Frage / Problem. Wie kann ich so Rechnung des Totalcost auf, dass es mit KVO / Bindungen funktioniert, wenn eine der Kosten der Position geändert?
Ich habe versucht, die Einrichtung:
+ (NSSet *)keyPathsForValuesAffectingTotalCost {
return [NSSet setWithObjects:@"lineItems.cost", nil];
}
, aber es funktioniert nicht. Ich am Ende mit einem Fehler in der Konsole: [<NSCFArray 0x1499ff40> addObserver:forKeyPath:options:context:] is not supported. Key path: cost
Lösung
Ich glaube nicht, zu viele Beziehungen zum automatischen propogation KVO unterstützt werden. Die Dokumentation sagt nicht ausdrücklich eine oder andere Weise, aber von dem, was ich weiß, von KVO im Allgemeinen beobachtete Subkeys eines n-Beziehung neigt nicht-trivial zu sein.
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 sind, und dann die Änderung totalCost
manuell auslösen willChangeValueForKey Verwendung: / didChangeValueForKey :. So etwas wie dieser (skizzenhafte Code, Haftungsausschluss 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"];
}
}
Andere Tipps
Sie können eine kürzere Lösung versuchen.
Inzu der Header-Datei:
@property (retain, readonly) NSDecimalNumber *accountBalance;
In zur Umsetzung Datei
- (NSDecimalNumber *)totalCost
{
return [self valueForKeyPath:@"InvoiceLineItems.@sum.cost"];
}