少し前に一時的なプロパティを使い始めて、かなりよく理解していると思いましたが、これは思ったとおりに動作していません。これは、データモデルで未定義の型を持つ一時的なプロパティとして定義されており、次のようにプロパティとして宣言されています。
@property (nonatomic, readonly) NSSet * manufacturers;
このプロパティは、このオブジェクトの別の1:M関係に依存するように宣言されています。
+ (NSSet *) keyPathsForValuesAffectingManufacturers
{
return [NSSet setWithObject:@"lines"];
}
この一時的なプロパティに対して、かなり標準的なゲッターを実装しました。
- (NSSet *) manufacturers
{
[self willAccessValueForKey:@"manufacturers"];
NSSet *mfrs = [self primitiveManufacturers];
[self didAccessValueForKey:@"manufacturers"];
if (mfrs == nil)
{
NSMutableSet *working = [NSMutableSet set];
/* rebuild the set of manufacturers into 'working' here */
mfrs = working;
[self setPrimitiveManufacturers:mfrs];
}
return mfrs;
}
機能していない部分は、オブジェクトがこのオブジェクトのリレーションシップに追加/削除されたときに、のキャッシュされたプリミティブ値が消去されてmanufacturers
いないように見えることです。lines
行を追加/削除するmanufacturers
とアクセサーが確実に呼び出されますが、[self primitiveManufacturers]
それでも古いキャッシュ値(明らかにnilではない)が返されるため、現在のメーカーのセットを再構築するコードは呼び出されず、結果としてout- of-dateの戻り値。
キャッシュされた一時的なプロパティ値がどのように機能するかについて何か誤解していますか?または、ある種のKVOコールバックによって行が変更されたときに、キャッシュされた値を手動で無効にして、次にmanufacturers
アクセスされたときに「if」内の更新コードが実行されるようにする必要がありますか?
どんな助けでも大歓迎です。
編集:私は基本的にこの一時的なプロパティとの1:Mの関係(つまり、より良い言葉を求めて一時的な関係)をシミュレートしていることを認識しています。また、ドキュメントsetPrimitiveValue:forKey:
が関係に使用することに対して警告していることも認識しています。
通常、このメソッドは、関係ではなく、属性(通常は一時的)を変更する場合にのみ使用する必要があります。新しいNSMutableSetオブジェクトに多対多の関係を設定しようとすると、(最終的には)失敗します。このメソッドを使用して関係を変更する必要があるという異常なイベントでは、最初にprimitiveValueForKeyを使用して既存のセットを取得し(メソッドがnilを返さないことを確認します)、可変コピーを作成してから、コピーを変更します
ただし、実際の1:M関係にプリミティブ値を設定しておらず、シミュレートされた一時的な関係のみを設定しているため、この警告は私のユースケースには当てはまらないと想定していました。
編集#2:オブジェクトがセットに追加またはセットから削除されたときにのみ追跡しようとしているためlines
(これは、の期待値manufacturers
が変更される唯一の方法です)、すでに存在するオブジェクトの属性の更新を追跡しようとしているのではありませんセット、私はlines
これほど重いものは必要ないと思います:https ://github.com/mbrugger/CoreDataDependentProperties
解決策:以下の回答に照らして、更新manufacturers
時にセットを空白にする次の解決策を実装しました。lines
誰かがこれに関する問題を見ることができますか、またはそれを実装するためのより効率的な方法を提案できますか?この操作はメインスレッドで実行されるため、高速であることが重要です。また、更新の実行と同時に発生するUIの更新が目に見えて遅延しline
ます。
- (void) awakeFromFetch
{
[super awakeFromFetch];
[self addObserver:self forKeyPath:@"lines" options:0 context:nil];
}
- (void) awakeFromInsert
{
[super awakeFromInsert];
[self addObserver:self forKeyPath:@"lines" options:0 context:nil];
}
- (void) didTurnIntoFault
{
[self removeObserver:self forKeyPath:@"lines"];
[super didTurnIntoFault];
}
- (void) observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([object isEqual:self] && [keyPath isEqualToString:@"lines"])
{
[self setPrimitiveManufacturer:nil];
}
else
{
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
}