4

少し前に一時的なプロパティを使い始めて、かなりよく理解していると思いましたが、これは思ったとおりに動作していません。これは、データモデルで未定義の型を持つ一時的なプロパティとして定義されており、次のようにプロパティとして宣言されています。

@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];
    }
}
4

1 に答える 1

1

keyPathsForValuesAffectingManufacturersは、行が変更されたときに製造元の値が削除されることを意味するのではなく、行が変更されたときに製造元を監視するオブジェクトに通知する必要があることを意味します。これは、あるプロパティが別のプロパティに基づいてその値を取得するときに使用されます。あなたの状況では、ラインを変更するときにメーカーを変更する必要があります。

于 2011-01-04T01:59:14.460 に答える