5

次のように定義されたNSManagedObjectContextのGCDディスパッチキューで操作を行っています。

- (NSManagedObjectContext *)backgroundContext
{
    if (backgroundContext == nil) {
        self.backgroundContext = [NSManagedObjectContext MR_contextThatNotifiesDefaultContextOnMainThread];
    }
    return backgroundContext;
}

MR_contextThatNotifiesDefaultContextOnMainThreadMagicalRecordのメソッドです:

NSManagedObjectContext *context = [[self alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[context setParentContext:[NSManagedObjectContext MR_defaultContext]];
return context;

オブジェクトをフェッチして正しいキュー位置を指定した後、それらをログに記録し、順序は正しいです。ただし、2番目のログは完全にランダムであるように見え、ソート記述子は明らかに機能していません。

問題をに絞り込みました[self.backgroundContext save:&error]。バックグラウンドコンテキストを保存した後、ソート記述子が壊れます。

dispatch_group_async(backgroundGroup, backgroundQueue, ^{
    // ...

    for (FooObject *obj in fetchedObjects) {
        // ...
        obj.queuePosition = [NSNumber numberWithInteger:newQueuePosition++];
    }

    NSFetchRequest *f = [NSFetchRequest fetchRequestWithEntityName:[FooObject entityName]];
    f.predicate = [NSPredicate predicateWithFormat:@"queuePosition > 0"];
    f.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"queuePosition" ascending:YES]];
    NSArray *queuedObjects = [self.backgroundContext executeFetchRequest:f error:nil];
    for (FooObject *obj in queuedObjects) {
        DLog(@"%@ %@", obj.queuePosition, obj.title);
    }

    if ([self.backgroundContext hasChanges]) {
        DLog(@"Changes");
        NSError *error = nil;
        if ([self.backgroundContext save:&error] == NO) {
            DLog(@"Error: %@", error);
        }
    }

    queuedObjects = [self.backgroundContext executeFetchRequest:f error:nil];
    for (FooObject *obj in queuedObjects) {
        DLog(@"%@ %@", obj.queuePosition, obj.title);
    }

});

ソート記述子が機能しない理由がわかりません。コアデータの専門家が助けてくれませんか?

アップデート:

この問題はiOS4では発生しません。理由はスレッド分離モードとプライベートキューモードの違いにあると思います。MagicalRecordは、動作が異なるように見える新しい同時実行パターンを自動的に使用します。

アップデート2:

この問題は、バックグラウンドコンテキストの保存を追加することで解決されました。

if ([[NSManagedObjectContext MR_contextForCurrentThread] hasChanges]) {
    DLog(@"Changes");
    NSError *error = nil;
    if ([[NSManagedObjectContext MR_contextForCurrentThread] save:&error] == NO) {
        DLog(@"Error: %@", error);
    } else {
        NSManagedObjectContext *parent = [NSManagedObjectContext MR_contextForCurrentThread].parentContext;
        [parent performBlockAndWait:^{
            NSError *error = nil;
            if ([parent save:&error] == NO) {
                DLog(@"Error saving parent context: %@", error);
            }
        }];
    }
}

アップデート3:

MagicalRecordは、コンテキストを再帰的に保存するメソッドを提供します。これで、私のコードは次のようになります。

if ([[NSManagedObjectContext MR_contextForCurrentThread] hasChanges]) {
    DLog(@"Changes");
    [[NSManagedObjectContext MR_contextForCurrentThread] MR_saveWithErrorHandler:^(NSError *error) {
        DLog(@"Error saving context: %@", error);
    }];
}

そもそも使わなかったのが恥ずかしい…

しかし、なぜこれが役立つのかわかりません。説明を求めています。

4

3 に答える 3

2

MagicalRecordを書いたので、コメントしようと思います。

そのため、iOS5では、MagicalRecordは、複数の管理対象オブジェクトコンテキストの新しいプライベートキューメソッドを使用しようとするように設定されています。これは、子コンテキストでの保存は、親にのみ保存をプッシュすることを意味します。親がもういない親が保存した場合にのみ、保存はそのストアに保持されます。これはおそらく、MagicalRecordのバージョンで起こっていたことです。

MagicalRecordは、以降のバージョンでこれを処理しようとしました。つまり、プライベートキューモードとスレッド分離モードのどちらかを選択しようとします。ご存知のように、それはあまりうまく機能しません。iOS4およびiOS5用の(複雑なプリプロセッサルールなどを使用せずに)コードを記述するための真に互換性のある唯一の方法は、従来のスレッド分離モードを使用することです。1.8.3タグのMagicalRecordはそれをサポートしており、両方で機能するはずです。2.0以降は、以降はプライベートキューのみになります。

また、MR_saveメソッドを見ると、hasChangesチェックも実行されていることがわかります(Core Data内部でも処理できるため、これも不要な場合があります)。とにかく、あなたが書いて維持しなければならないコードが少なくて済みます...

于 2012-04-13T10:59:31.027 に答える
1

元の設定が機能しなかった実際の根本的な理由は、親コンテキストがまだストアに保存されていないときに、ソート記述子を使用して子コンテキストからフェッチするときのAppleのバグです。

NSSortdescriptorは、NSManagedContextからの結果のフェッチに無効です

ネストされたコンテキストを回避できる方法がある場合は、それらがまだ非常にバグが多く、想定されるパフォーマンスの向上に失望する可能性があるため、回避してください。また: http ://wbyoung.tumblr.com/post/27851725562/core-data-growing-pains

于 2012-12-11T08:23:58.137 に答える
-2

CoreDataはセーフスレッドフレームワークではなく、スレッド(操作キュー)ごとに異なるため、コアデータは異なるコンテキストを使用します。次の優れた文章を参照してください

http://www.duckrowing.com/2010/03/11/using-core-data-on-multiple-threads/

于 2012-04-12T10:02:17.100 に答える