Настройка KVO для рассчитанных значений, основанных на рассчитанных значениях

StackOverflow https://stackoverflow.com/questions/612474

Вопрос

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

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

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

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

Теперь мой вопрос / проблема. Как настроить Invoice's totalCost, чтобы он работал с KVO / привязками, когда изменилась стоимость одной позиции?

Я попытался настроить:

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

но это не работает. Я получаю сообщение об ошибке в консоли: [<NSCFArray 0x1499ff40> addObserver:forKeyPath:options:context:] is not supported. Key path: cost

Это было полезно?

Решение

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

Я хотел бы подойти к этому вручную, наблюдая свойство cost каждого объекта InvoiceLineItem, реализуя многие методы доступа KVC для свойства lineItems класса Invoice, выполняя вызов 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"];
    }
}

Другие советы

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

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

@property (retain, readonly) NSDecimalNumber *accountBalance;

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

- (NSDecimalNumber *)totalCost
{
    return [self valueForKeyPath:@"InvoiceLineItems.@sum.cost"];
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top