2009-03-04 18 views
9

Mam więc dwa obiekty, fakturę i fakturęLineItem. InvoiceLineItem ma właściwość o nazwie cost i jest dynamicznie tworzona na podstawie innych właściwości. Aby uzyskać pomoc dotyczącą KVO/powiązań, których używam:Ustawienie KVO dla obliczonych wartości, na podstawie obliczonych wartości

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

Działa to świetnie. Kiedy edytuję właściwość taką jak komenda serivceCost, główny koszt w widoku tabeli będzie aktualizowany poprawnie.

W obiekcie faktury mam NSMutableArray of InvoiceLineItems. Faktura ma podobną właściwość o nazwie totalCost. Jest on obliczany na podstawie powtarzania elementów zamówienia i dopóki element zamówienia nie jest oznaczony jako usunięty (co robię ze względu na synchronizację), sumuje koszty i tworzy totalCost.

Teraz moje pytanie/problem. Jak skonfigurować łączny koszt faktury, aby działał z KVO/powiązaniami, gdy zmienił się jeden z kosztów elementu zamówienia?

Próbowałem konfigurowania:

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

ale to nie działa. Kończy się błąd w konsoli: [<NSCFArray 0x1499ff40> addObserver:forKeyPath:options:context:] is not supported. Key path: cost

Odpowiedz

6

Nie wierzę, że wiele relacji jest obsługiwanych dla automatycznej propagacji KVO. Dokumentacja nie mówi explicity w ten czy w inny sposób, ale z tego, co wiem o KVO w ogóle, obserwowanie podklucze relacji "wiele do wielu" wydaje się być nietrywialne.

Sposób Chciałbym podejść do tego byłoby ręcznie obserwować właściwość każdego obiektu InvoiceLineItem cost, poprzez wdrożenie do wielu akcesorów KVC dla właściwości lineItems na klasy faktury robi addObserver/call removeObserver we wkładce/usuń metody, a następnie wywołaj zmianę totalCost ręcznie przy użyciu metody willChangeValueForKey:/didChangeValueForKey :. Tak więc coś takiego (z grubsza zarysowany kod, zastrzeżenia itp.):

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

byłem dość blisko do tego rodzaju realizacji siebie, ale dobrze jest usłyszeć pochodzić od kogoś innego. Pytanie jednak, układanie woli/didChange ... dlaczego nie zadzwonić do didChange? – zorn

+0

Myślę, że to powinno działać, jeśli podstawowe obiekty implementują je poprawnie. Na przykład w sekcji Najczęstsze pytania dotyczące danych podstawowych znajduje się coś takiego: http://developer.apple.com/documentation/Cocoa/Conceptual/CoreData/Articles/cdFAQ.html#//apple_ref/doc/uid/TP40001802-SW3 –

+0

Z kilkoma wczesnymi testami to działa. Miałem już większość rzeczy obserwacyjnych na miejscu (dla cofnięcia wsparcia). Dzięki jeszcze raz. – zorn

0

Możesz spróbować krótszego rozwiązania.

Dodaj do pliku nagłówka:

@property (retain, readonly) NSDecimalNumber *accountBalance; 

Dodaj do pliku wdrażania

- (NSDecimalNumber *)totalCost 
{ 
    return [self valueForKeyPath:@"[email protected]"]; 
} 
Powiązane problemy