ドキュメントベースのCoreDataアプリケーション(Mac OS X 10.5以降で実行)がありNSManagedObjectContext
、メインスレッドで2つを使用しようとしています。セカンダリコンテキストで行われた変更をメイン(プライマリ)コンテキストにマージしたいと思います。さらに、セカンダリコンテキストからマージされた変更を元に戻して、ドキュメントに「ダーティ」のマークを付ける必要があります。私の質問は「メインスレッドから実行されるコアデータの挿入を元に戻す」に似ていると思いますが、ATMでは別のスレッドを使用していません。
私はNSManagedObjectContextDidSaveNotification
次のように(呼び出し時に2番目のコンテキストから送信される)を観察してきました-[self.secondaryContext save:]
:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mocDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:self.secondaryContext];
-mocDidSave:
オブザーバーによって呼び出されたメソッドでは、プライマリコンテキストで使用-[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:]
して、セカンダリコンテキストからプライマリコンテキストへの変更をマージしようとしました。
- (void)mocDidSave:(NSNotification *)notification
{
[self.primaryContext mergeChangesFromContextDidSaveNotification:notification];
}
ただし、たとえば、挿入されたオブジェクトはアレイコントローラにすぐに表示されますが、ドキュメントはダーティとしてマークされておらずisInserted
、新しく追加された管理対象オブジェクトのプロパティはYESに設定されていません。また、(プライマリコンテキストへの)挿入は元に戻せません。
挿入されたオブジェクトを再フォールトすると、少なくともドキュメントがダーティとしてマークされますが、挿入は元に戻せません。
- (void)mocDidSave:(NSNotification *)notification
{
[self.primaryContext mergeChangesFromContextDidSaveNotification:notification];
for (NSManagedObject *insertedObject in [[notification userInfo] objectForKey:NSInsertedObjectsKey]) {
[self.primaryContext refreshObject:[self.primaryContext existingObjectWithID:[insertedObject objectID] error:NULL] mergeChanges:NO];
}
}
Wrt -mocDidSave:
、カスタム実装で少し良い結果が得られました:
- (void)mocDidSave:(NSNotification *)notification
{
NSDictionary *userInfo = [notification userInfo];
NSSet *insertedObjects = [userInfo objectForKey:NSInsertedObjectsKey];
if ([insertedObjects count]) {
NSMutableArray *newObjects = [NSMutableArray array];
NSManagedObject *newObject = nil;
for (NSManagedObject *insertedObject in insertedObjects) {
newObject = [self.primaryContext existingObjectWithID:[insertedObject objectID] error:NULL];
if (newObject) {
[self.primaryContext insertObject:newObject];
[newObjects addObject:newObject];
}
}
[self.primaryContext processPendingChanges];
for (NSManagedObject *newObject in newObjects) {
[self.primaryContext refreshObject:newObject mergeChanges:NO];
}
}
NSSet *updatedObjects = [userInfo objectForKey:NSUpdatedObjectsKey];
if ([updatedObjects count]) {
NSManagedObject *staleObject = nil;
for (NSManagedObject *updatedObject in updatedObjects) {
staleObject = [self.primaryContext objectRegisteredForID:[updatedObject objectID]];
if (staleObject) {
[self.primaryContext refreshObject:staleObject mergeChanges:NO];
}
}
}
NSSet *deletedObjects = [userInfo objectForKey:NSDeletedObjectsKey];
if ([deletedObjects count]) {
NSManagedObject *staleObject = nil;
for (NSManagedObject *deletedObject in deletedObjects) {
staleObject = [self.primaryContext objectRegisteredForID:[deletedObject objectID]];
if (staleObject) {
[self.primaryContext deleteObject:staleObject];
}
}
[self.primaryContext processPendingChanges];
}
}
これにより、アレイコントローラが更新され、ドキュメントがダーティとしてマークされ、挿入と削除が元に戻されます。ただし、まだ元に戻せない更新については、まだ問題があります。代わりに、すべてのupdatedObjectsを手動でループし-[NSManagedObject changedValues]
、プライマリコンテキストで変更を再適用するために使用する必要がありますか?
もちろん、このカスタム実装は、メインコンテキストのセカンダリコンテキストから多くの作業を複製します。マージを元に戻すことができるステップとして維持しながら、2つのコンテキスト間のマージを取得する他の/より良い方法はありますか?