9

所以我有两个对象,Invoice 和 InvoiceLineItem。InvoiceLineItem 有一个名为的属性cost,它是基于其他属性动态创建的。为了帮助我使用 KVO/绑定:

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

这很好用。当我编辑像 serivceCost 这样的属性时,表视图中的主要成本会更新得很好。

在 Invoice 对象中,我有一个 InvoiceLineItems 的 NSMutableArray。Invoice 有一个类似的属性,称为totalCost. 它是通过迭代行项目来计算的,只要行项目没有被标记为已删除(我这样做是出于同步原因),它就会将成本相加并创建总成本。

现在我的问题/问题。如何设置 Invoice 的 totalCost 以便在行项目的成本之一发生更改时它与 KVO/绑定一起使用?

我尝试设置:

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

但它不起作用。我最终在控制台中出现错误:[<NSCFArray 0x1499ff40> addObserver:forKeyPath:options:context:] is not supported. Key path: cost

4

2 回答 2

6

我不相信自动 KVO 传播支持多关系。文档并没有以一种或另一种方式明确说明,但从我对 KVO 的一般了解来看,观察一对多关系的子键往往不是微不足道的。

我解决这个问题的方法是手动观察cost每个 InvoiceLineItem 对象的属性,通过在 Invoice 类上分别执行 addObserver/removeObserver 调用的属性的一对多 KVC 访问器lineItems在插入/删除方法中调用,然后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"];
    }
}
于 2009-03-04T21:35:15.507 回答
0

您可以尝试更短的解决方案。

添加到头文件:

@property (retain, readonly) NSDecimalNumber *accountBalance;

添加到实现文件

- (NSDecimalNumber *)totalCost
{
    return [self valueForKeyPath:@"InvoiceLineItems.@sum.cost"];
}
于 2009-09-04T13:53:44.430 回答