計算値に基づいた計算値用のKVOのセットアップ
-
03-07-2019 - |
質問
つまり、InvoiceとInvoiceLineItemの2つのオブジェクトがあります。 InvoiceLineItemにはcost
というプロパティがあり、他のプロパティに基づいて動的に作成されます。私が使用するKVO /バインディングを支援するには:
+ (NSSet *)keyPathsForValuesAffectingCost {
return [NSSet setWithObjects:@"lineItemType", @"serviceCost", @"hourlyRate", @"timeInSeconds", @"productCost", @"quantityOfProduct", @"mileageCost", @"milesTraveled", nil];
}
これはうまく機能します。 serivceCostのようなプロパティを編集すると、テーブルビューのメインコストは正常に更新されます。
Invoiceオブジェクトには、InvoiceLineItemsのNSMutableArrayがあります。請求書には、totalCost
という同様のプロパティがあります。これは、広告申込情報を反復処理することで計算され、広告申込情報が削除済みとしてマークされていない限り(同期の理由で)、コストが加算され、totalCostが作成されます。
今私の質問/問題。ラインアイテムのコストの1つが変更されたときにInvoiceのtotalCostを設定して、KVO /バインディングで機能するようにするにはどうすればよいですか?
設定しようとしました:
+ (NSSet *)keyPathsForValuesAffectingTotalCost {
return [NSSet setWithObjects:@"lineItems.cost", nil];
}
しかし機能しません。コンソールにエラーが表示されます:[<NSCFArray 0x1499ff40> addObserver:forKeyPath:options:context:] is not supported. Key path: cost
解決
自動KVO伝播では、多対多の関係がサポートされているとは思わない。ドキュメントではどちらかと言えば明示的に述べていませんが、KVOについて一般的に知っていることから、多対多の関係のサブキーを観察することは簡単ではありません。
これにアプローチする方法は、各InvoiceLineItemオブジェクトの cost
プロパティを手動で観察することです。これには、 lineItems
プロパティのそれぞれinsert / removeメソッドでaddObserver / removeObserver呼び出しを行う請求書クラスは、willChangeValueForKey:/ didChangeValueForKey:を使用して totalCost
の変更を手動でトリガーします。そのため、次のようなもの(おおまかにスケッチしたコード、免責事項など):
- (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"];
}