2009-03-04 5 views
9

Итак, у меня есть два объекта: Invoice и InvoiceLineItem. InvoiceLineItem имеет свойство, называемое cost, и оно динамически создается на основе других свойств. Чтобы помочь с KVO/креплениями, я использую:Настройка KVO для вычисленных значений на основе вычисленных значений

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

Это прекрасно работает. Когда я редактирую свойство вроде serivceCost, основная стоимость в представлении «Просмотр таблицы» прекрасна.

В объекте Invoice у меня есть NSMutableArray из InvoiceLineItems. Счет-фактура имеет аналогичное свойство, называемое totalCost. Он рассчитывается путем итерации по позициям и до тех пор, пока позиция не будет помечена как удаленная (что я делаю для синхронизации причин), она добавляет затраты и создает totalCost.

Теперь мой вопрос/вопрос. Как настроить TotalCost счета-фактуры так, чтобы он работал с KVO/привязками при изменении одной из затрат на позицию?

Я попытался создать:

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

, но он не работает. В итоге у меня возникла ошибка в консоли: [<NSCFArray 0x1499ff40> addObserver:forKeyPath:options:context:] is not supported. Key path: cost

ответ

6

Я не верю, что многие отношения поддерживаются для автоматической передачи KVO. Документация не говорит об одной или той же причине, но из того, что я знаю о KVO в целом, наблюдаемые подразделы отношения ко многим относятся к нетривиальным.

Пути я бы подойти к этому было бы вручную наблюдать cost свойства каждого объекта InvoiceLineItem, путем реализации КВЦ аксессоров ко многим для lineItems собственности на классе счетов делают в addObserver/removeObserver вызов вставки/удаление методов, а затем запускаем изменение totalCost вручную, используя willChangeValueForKey:/didChangeValueForKey :. Так что-то вроде этого (примерно набросанный код, отказ от ответственности и т. Д.):

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

Я был очень близок к этому виду реализации себя, но это хорошо, чтобы услышать его прийти от кого-то другого. Вопрос, хотя, укладка will/didChange ... почему бы просто не позвонить didChange? – zorn

+0

Я думаю, что он должен работать, если базовые объекты реализуют его правильно. Например, в разделе «Часто задаваемые вопросы по основным данным» отображается примерно так: http://developer.apple.com/documentation/Cocoa/Conceptual/CoreData/Articles/cdFAQ.html#//apple_ref/doc/uid/TP40001802-SW3 –

+0

С некоторыми ранними испытаниями это работает. У меня уже было больше всего материала для наблюдения (для поддержки отмены). Еще раз спасибо. – zorn

0

Вы можете попробовать короткое решение.

Добавить в заголовочный файл:

@property (retain, readonly) NSDecimalNumber *accountBalance; 

Добавить в файл реализации

- (NSDecimalNumber *)totalCost 
{ 
    return [self valueForKeyPath:@"[email protected]"]; 
} 
Смежные вопросы