2013-03-07 78 views
8

OK,這是推動我堅果。NSMergeConflict(兩個線程) - 設置合併策略不能解決

我有使用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)爲NSManagedObject(0x119aea80)用的objectID '0x9dcec90' 與oldVersion = 10和NEWVERSION = 11老對象快照= {\ n的displayName = \ 「\」; \ n MACHINENAME = KIYGRDRTTDVLTQB; \注意= \ 「\」; \ n產品= \ 「0x11967ab0 \」; \ n公共= 1; \ n出版= 1; \ n數量= 3; \ n registeredTo = \ 「\」; \ n registeredToEmail = \ 「\」; \ n registeredToNote = \ 「\」; \ n狀態= \ 「ON REGISTRY \」; \ n更新= \ 「2013年3月7日10時22分01秒0000 \」; \ n的心願= \ 「\」; \ N}和新緩存行= {\ n的displayName = \ 「\」; \ n MACHINENAME = KIYGRDRTTDVLTQB; \ n note = \「\」; \ n product = \「0x1a9ee3d0 \」; \ n pub lic = 1; \ n published = 1; \ n quantity = 3; \ n registeredTo = \「\」; \ n registeredToEmail = \「\」; \ n registeredToNote = \「\」; \ n status = \「ON REGISTRY \「; \ n upDate = \」2013-03-07 10:22:03 +0000 \「; \ n wishList = \」\「; \ n}」 ); }

順便說一句,我看到的新舊對象之間唯一的區別是指向「產品」的指針。 這可能是我的問題嗎?

另一個可能的線索是,這種情況只與新添加的對象,而且是在後臺同步發生。 如果我停止應用程序並重新加載它(重新加載持久性存儲),我現在可以編輯沒有問題的現有對象,並按照我喜歡的順序同步多次,沒有任何問題。

謝謝你們

回答

19

OK啦,

一個月打破我的心在此之後 - 有一個解決方案,並沒有我也能猜到。我實際上開了一個支持蘋果的事件,他們解決了這個問題。

所以這裏有雲:

當設置爲主要管理對象上下文的合併策略,有一個叫parentContext屬性。我還不清楚這個屬性是什麼,因爲文檔很少。然而,這絕對解決了我的問題。 請注意,在我的工作流程中,我創建了一個NSManagedDocument並從中提取上下文。我認爲大多數人都是這樣做的(大多數人不使用manageddocument)。

而不是

[self.mainManagedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy]; 

我現在使用:

NSManagedObjectContext *parentContext = delegate.mainManagedObjectContext.parentContext; 
    [parentContext performBlockAndWait:^{ 
     [parentContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy]; 
    }]; 

塊的東西是一種預防措施,以確保這是在正確的線程執行的,重要的是設置合併策略到所需上下文的parentContext。

在個人筆記上,我必須添加兩個大的噓聲: 1.噓我,因爲使用NSManagedDocument,儘管它有點過時,只是因爲我找到了很好的例子。 2.對蘋果非常缺乏在該領域的文檔大噓。我花了數週閱讀了關於ManagedObjectContexts,今天是我第一次瞭解到parentContext屬性。

+0

嗨@llan lewin,請你看看這個鏈接http://stackoverflow.com/questions/19443853/nsmergeconflict-for-nsmanagedobject-with-single-managedobjectcontext – Ranjit 2013-10-18 12:12:23

+0

首先謝謝!這絕對解決了我的問題。關於父上下文,您可以通過以下網址閱讀它們:https://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/UsingCoreDataWithiCloudPG/UsingCoreDataWithiCloudPG.pdf(section:Using a Managed Document's Managed Object Context。) – 2014-05-05 10:04:22

+0

嗨伊蘭,在你的答案你已經提到這種方法(即設置合併策略在performBlockAndWait)是非常有用的,當你通過創建NSManagedDocument獲取上下文。我沒有使用這個工作流程。我應該在我的工作流程中添加這個嗎? OR還有其他方法嗎? – Arun 2016-07-13 13:04:38