15

Webサーバーからデータを取得し、と呼ばれる子のプライベートバックグラウンドコンテキストで処理していますbackgroundMOCmainMOCこれはメインUIにリンクされているの子であるため、backgroundMOCトリガーの保存によりUIが変更されます。は、永続ストアに関連付けられたプライベートバックグラウンドキューmainMOCであるaの子であるmasterMOCため、マスターに保存するとディスクに保存されます。

私が今していることは、データを受け取り、で新しいオブジェクトを作成しbackgroundMOC、次に保存backgroundMOC(UIが更新されるように)、保存mainMOC(ほとんどディスクに保存できるように)、そして保存masterMOC(最終的にディスクに書き込めるように)です。問題は、フェッチされた結果コントローラーを介してオブジェクトがUIに表示されてobjectIdも、それが一時的なものであるということです。

これにより、重複行の問題が発生します。サーバーから同じデータを(誤って)受け取った場合backgroundMOC、永続的なIDが割り当てられていないため、このオブジェクトがすでに存在していることがわからないため、別のオブジェクトが作成されます。アプリを再起動すると、重複するオブジェクトが消えるので、IDマッピングの問題であることがわかります。

だからやってみようかな

[backgroundMOC obtainPermanentIDsForObjects:backgroundMOC.registeredObjects.allObjects error:nil];

保存する前に(私も保存してみました)。ただし、何らかの理由で、この行を呼び出すと例外がスローされます。

CoreDataは次の障害を実行できませんでした...

私を正しい方向に導くかもしれないヒントがあれば、共有してください。ありがとう

編集:わかりました。最初は、masterMOCの子であるmainMOCの子であるbackgroundMOCでgetpermanentIDsForObjectsを呼び出していました。mainMOCでIDを取得するように切り替えたところ、すべての問題が解決しました(今のところ)。子コンテキストでgetpermIdsを呼び出すことは想定されていませんでしたか?

4

2 に答える 2

19

これは既知のバグ(新しいオブジェクトが保存されたときにネストされたコンテキストが永続的なIDを取得しない)である可能性があり、今後のリリースで修正される予定です...

ただし、永続的なIDを要求できるはずですが、挿入されたオブジェクトでのみ要求する必要があります。

[moc obtainPermanentIDsForObjects:moc.insertedObjects.allObjects error:0];

ただし、永続IDを取得せずに保存すると、一時IDが親コンテキストに伝播されるため、MOCを保存する前にこれを行う必要があります。たとえば、mainMocに保存してからIDSを取得する場合、backgroundMOCにはまだ一時IDが残っているため、今後保存すると重複データが作成されます。

永続IDの取得はデータベースにまで及ぶことに注意してください。ただし、メインMOCの子MOCで取得する場合は、これが発生している間はメインスレッドをまったくブロックしないでください。

したがって、最低レベルのMOCからの保存では、このようなものを効果的に使用する必要があります(もちろん、適切なエラー処理を使用します)...

[backgroundMoc performBlock:^{
    [backgroundMoc obtainPermanentIDsForObjects:backgroundMoc.insertedObjects.allObjects error:0];
    [backgroundMoc save:0];
    [mainMoc performBlock:^{
       [mainMoc save:0];
        [masterMoc performBlock:^{
            [masterMoc save:0];
        }];
    }];
}];

必要に応じて、他にもプレイできるゲームがいくつかあります。

これに似たNSManagedObjectのカテゴリを提供します...

@implementation NSManagedObject (initWithPermanentID)
- (id)initWithEntity:(NSEntityDescription *)entity insertWithPermanentIDIntoManagedObjectContext:(NSManagedObjectContext *)context {
    if (self = [self initWithEntity:entity insertIntoManagedObjectContext:context]) {
        NSError *error = nil;
        if (![context obtainPermanentIDsForObjects:@[self] error:&error]) {
            @throw [NSException exceptionWithName:@"CoreData Error" reason:error.localizedDescription userInfo:error.userInfo];
        }
    }
    return self;
}

+ (NSArray*)createMultipleObjects:(NSUInteger)count withEntity:(NSEntityDescription *)entity inManagedObjectContext:(NSManagedObjectContext *)context {
    NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];
    for (NSUInteger i = 0; i < count; ++i) {
        [array addObject:[[self alloc] initWithEntity:entity insertIntoManagedObjectContext:context]];
    }
    NSError *error = nil;
    if (![context obtainPermanentIDsForObjects:array error:&error]) {
        @throw [NSException exceptionWithName:@"CoreData Error" reason:error.localizedDescription userInfo:error.userInfo];
    }
    return array;
}
@end

さて、最初のものでは、データベースにアクセスして、作成された各エンティティのIDを作成するためにお金を払っていますが、それほど多くはなく、バックグラウンドスレッドで発生しており、各ディップは短いです...

まあ、それは最高ではありませんが、それは便利です。さらに、2つ目は同じオブジェクトを複数作成し、それらの永続IDを同時に取得します。

PSCに直接接続されたMOCを使用して、DidChangeイベントを監視することもできますが、これは以前の方法と同じです。

残念ながら、別のMOCでpersistentID要求を作成してObjectIDを渡すことはできませんが、別のMOCでDBにプロトタイプオブジェクトを作成し、それらのObjectIDを提供することはできます。

プロトタイプファクトリはかなり一般的なパターンであり、そのルートをたどると、最終的なバグ修正がここに到達したときに小さな変更を加えるのは非常に簡単です。

編集

スヴェンに応えて...

新しい複雑なグラフを作成する場合は、作成直後に永続的なIDを取得する必要があります。ストアへのヒット数を減らすには、それらをすべて作成し、一度にIDを取得してから、それらを接続し始める必要があります。

正直なところ、これはすべて、現在存在するバグを回避することです。これらのバグは、中小規模の更新で回避する価値があります。バグが修正されたとき、コードは同じになります(取得はありません)。したがって、小規模なインポートにはこの方法をお勧めします。

大規模な更新を行う場合は、「古い」方法を使用することをお勧めします。PSCに直接接続された新しいMOCを作成します。そこですべての変更を行い、「ライブ」コンテキストをそれらのDidSave通知からマージするだけです。

最後に、永続IDのデータベースへの影響について。MOCを破棄してもかまいません。ディスクがヒットし、メタデータが変更されますが、オブジェクトは保持されません。

正直なところ、結果として空きスペースがあるかどうかを確認するための大規模なテストは行いませんでした。そのため、それを実行して、私と一緒に戻ってください。

ディスク上の実際のデータベースファイルサイズを確認してから、10000個のオブジェクトを作成し、永続IDを取得して、MOCを解放し、サイズをもう一度確認します。

影響がある場合は、オブジェクトを削除してみるか、大規模な更新後にデータベースでバキュームを実行して、それが機能するかどうかを確認できます。

捨てるだけのオブジェクトをたくさん作成する場合は、データベースにアクセスする必要はありません。PSCに直接接続して、古い忠実な通知を使用することをお勧めします。

于 2012-08-16T22:15:15.870 に答える
1

フォアグラウンドスレッドとバックグラウンドスレッドの間で作業しているときに、CoreDataでさまざまなフラストレーションを経験しました。私が遭遇した問題の1つの解決策を探す際に

マジカルレコード

ドキュメントとメソッドを確認するのに少し時間を費やしましたが、CoreDataの操作が非常に簡単になったと言えます。具体的には、複数のコンテキストとスレッドを管理するのにも役立ちます。

あなたはそれをチェックしたいかもしれません。

于 2012-08-16T13:52:33.740 に答える