好的,这让我疯了。
我有两个使用UImanageddocument的线程,一个在用户进行选择的主上下文中,后台线程有自己的moc,根据时间戳将数据与服务器同步。
所有似乎都运作良好,但是当我: 1.在主上下文中添加一个对象 2.在后台同步 3.从后台保存 4.尝试再次更改同一个对象,现在从主要上下文 - 主线程
我得到了NSMergeConflict
我将包括我的一些代码,排除很多不相关的代码,向您展示我如何初始化上下文,希望有人可以启发我。我知道这些领域的核心数据很棘手。
在主线程上(在applicationdidfinishloadingwithoptions中):
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject]; //get the default user documents folder
url = [url URLByAppendingPathComponent:DATABASENAME];
UIManagedDocument *doc = [[UIManagedDocument alloc] initWithFileURL:url];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
doc.persistentStoreOptions = options;
[doc.managedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
self.database=doc;
self.mainManagedObjectContext=self.database.managedObjectContext;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDataModelChange:) name:NSManagedObjectContextObjectsDidChangeNotification object:self.database.managedObjectContext];
后来:
- (void)handleDataModelChange:(NSNotification *)note
{
[self save];
}
-(void) save
{
[self.database saveToURL:self.database.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success) {
batch_save=!success;
NSLog(@"save success %d",success);
}];
}
在后台主题:
dispatch_queue_t fetchQ = dispatch_queue_create("syncing list", NULL);
dispatch_async(fetchQ, ^ // *********** BACKGROUND THREAD ***********
{
AppDelegate *delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
NSManagedObjectContext *backgroundMOC2;
backgroundMOC2=[[NSManagedObjectContext alloc] init];
[backgroundMOC2 setPersistentStoreCoordinator:delegate.mainManagedObjectContext.persistentStoreCoordinator];
[backgroundMOC2 setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[delegate.mainManagedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[[NSNotificationCenter defaultCenter] addObserver:delegate.mainManagedObjectContext selector:@selector(mergeChangesFromContextDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:backgroundMOC2];
** pseudo-code:
perform fetch request from CD
submit data to server with POST request (synchronously)
retrieve JSON reply from server
update what's needed in CD objects
** end of pseudo code
[backgroundMOC2 save:nil];
[[NSNotificationCenter defaultCenter] removeObserver:delegate.mainManagedObjectContext name:NSManagedObjectContextDidSaveNotification object:backgroundMOC2];
});
dispatch_release(fetchQ);
我尝试过所有类型的合并策略常量都无济于事。
我收到此信息,文件未保存:
conflictList =( “NSMergeConflict(0x1a9ee1e0)for NSManagedObject(0x119aea80)with objectID'0x9dcec90'with oldVersion = 10 and newVersion = 11 and old object snapshot = {\ n displayName = \”\“; \ n machineName = KIYGRDRTTDVLTQB; \ n note = \” \“; \ n产品= \”0x11967ab0 \“; \ n public = 1; \ n已发布= 1; \ n数量= 3; \ n registeredTo = \”\“; \ n registeredToEmail = \”\“; \ n registeredToNote = \“\”; \ n status = \“ON REGISTRY \”; \ n upDate = \“2013-03-07 10:22:01 +0000 \”; \ n wishList = \“\”; \ n}和新的缓存行= {\ n displayName = \“\”; \ n machineName = KIYGRDRTTDVLTQB; \ n note = \“\”; \ n product = \“0x1a9ee3d0 \”; \ n public = 1; \ n已发布= 1; \ n数量= 3; \ n registeredTo = \“\”; \ n registeredToEmail = \“\”; \ n registeredToNote = \“\”; \ n status = \“ON REGISTRY \”; \ n upDate = \“2013-03-07 10:22:03 +0000 \”; \ n wishList = \“\”; \ n}“ ); }
BTW我在新旧对象之间看到的唯一区别是指向“产品”的指针。 这可能是我的问题吗?
另一个可能的线索是,这种情况只会在添加新对象时发生,并且仅在后台同步发生之后发生。 如果我停止应用程序并重新加载它(重新加载持久存储),我现在可以毫无问题地编辑现有对象,并且可以根据需要多次同步它,没有任何问题。
谢谢你们
答案 0 :(得分:19)
好的朋友,
经过一个月的思考 - 有一个解决方案,没有什么我猜的。我实际上向Apple开了一个支持事件,他们解决了这个问题。
所以这里是:
为主要托管对象上下文设置合并策略时,有一个名为parentContext的属性。我仍然不太清楚这个属性是什么,因为文档很少见。然而,这绝对解决了我的问题。 请考虑在我的工作流程中,我创建一个NSManagedDocument并从中提取上下文。我认为大多数人都是这样做(大多数人不使用托管文档)。
而不是
[self.mainManagedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
我现在用:
NSManagedObjectContext *parentContext = delegate.mainManagedObjectContext.parentContext;
[parentContext performBlockAndWait:^{
[parentContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
}];
块事物是一种预防措施,以确保在正确的线程中执行此操作,重要的是将合并策略设置为所需上下文的parentContext。
就个人而言,我必须加上两个大嘘声: 1.对我来说,使用NSManagedDocument虽然它有点过时,只是因为我找到了使用它的好例子。 对于苹果公司而言,该领域的文档非常缺乏。我花了几周阅读ManagedObjectContexts,今天是我第一次认识parentContext属性。