22

我的可可/應用程序在主線程上有一個託管對象上下文。 當我需要更新我的數據我的計劃將:核心數據合併兩個託管對象上下文

  1. 啓動一個新的線程
  2. 從服務器接收新的數據
  3. 創建一個新的託管對象上下文
  4. 將通知發送到主線程爲了合併兩個方面

這是接收主線程通知上的功能

- (void)loadManagedObjectFromNotification:(NSNotification *)saveNotification 
{ 
    if ([NSThread isMainThread]) { 
     [self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification]; 
    } else { 
     [self performSelectorOnMainThread:@selector(loadManagedObjectFromNotification:) withObject:saveNotification waitUntilDone:YES];  
    } 
} 

我沒有收到任何錯誤。 我的問題是合併結果,它實際上是從兩個上下文中連接管理對象。

我的實體是一個非常簡單的屬性和關係列表。

也許合併需要一些指令,以便了解何時更新的託管對象不是新的託管對象,而是第一個已編輯的版本。 我想我需要指定一種方式來明確地識別一個實體(例如屬性可以像一個ID),並像合併策略(如果2個託管對象代表相同的對象,採取與lastModificationDate更近)。

我只需要了解如何正確地合併2個上下文以便爲每個對象創建一個更新的副本。

UPDATE 1

問題現在已經清楚了。 2上下文有很大的區別:ObjectID。 雖然主線程上下文使用Persistent Store協調器獲取了ManagedObjects,但第二個線程通過獲取遠程URL來創建這些對象。即使對象具有相同的內容,它們也會有2個不同的對象ID。

我的對象已經有了一個唯一的標識符,我可以使用setObjectId來設置這個值。 (Apple文檔說這不是一個好主意)。

+1

很明顯,對象ID是不同的,因爲您正在創建對象,而不是從存儲中獲取並更新它們。這就是爲什麼我在回答中說,你不需要任何東西來合併對象。無論如何,處理這種情況的正確方法是使用託管對象ID。由於受管對象ID是線程安全的,因此可以將它們從主線程傳遞到另一個線程,然後使用existingObjectWithID:error:檢索與特定ID關聯的對象,更新它並保存上下文。現在合併將按照您的預期進行。 –

+0

或者,如果您事先不知道哪些受管對象ID必須在線程之間傳遞,那麼在其他線程中,您只需使用謂詞獲取對象以檢索與從服務器檢索到的對象相對應的對象,然後更新他們並保存上下文。 –

+0

正確!問題是objectIds。現在,每次我執行抓取並需要更新現有對象時,我都會從存儲中獲取對象並對其進行更新。 – Giuseppe

回答

32

以下是您需要做的以便正確合併上下文。 首先,你不需要你自己的通知。執行上保存上下文操作自動以下通知轉發給註冊的觀察者:

NSManagedObjectContextDidSaveNotification 

因此,所有你需要做的是:

在你的主線程1),可能會在viewDidLoad方法,註冊此通知:

[[NSNotificationCenter defaultCenter] addObserver:self 
             selector:@selector(contextDidSave:) 
              name:NSManagedObjectContextDidSaveNotification 
              object:nil]; 

2)實現你的主線程的contextDidSave:方法如下:

- (void)contextDidSave:(NSNotification *)notification 
{ 

    SEL selector = @selector(mergeChangesFromContextDidSaveNotification:); 
    [managedObjectContext performSelectorOnMainThread:selector withObject:notification waitUntilDone:YES]; 

} 

3)在dealloc方法添加以下內容:

[[NSNotificationCenter defaultCenter] removeObserver:self]; 

4)使用類似下面的方法在其他線程創建一個新的上下文:

- (NSManagedObjectContext*)createNewManagedObjectContext 
{ 

    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init]; 
    [moc setPersistentStoreCoordinator:[self persistentStoreCoordinator]]; 
    [moc setUndoManager:nil]; 
    return [moc autorelease]; 
} 

5)在收到新數據,處理這種情況的正確方法是使用託管對象ID。由於受管對象ID是線程安全的,因此可以將它們從主線程傳遞到另一個線程,然後使用existingObjectWithID:error:檢索與特定ID關聯的對象,並更新它並保存上下文。現在合併將按照您的預期進行。或者,如果您事先不知道哪些受管對象ID必須在線程之間傳遞,那麼在另一個線程中,您只需使用謂詞獲取對象以檢索與從服務器檢索到的對象相對應的對象,然後更新它們並保存上下文。

+0

這與我的實現非常相似。 我的問題是合併。當我打電話給 [self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification]; 它應該合併我的ManagedObjects,但它只是做一個串聯。 – Giuseppe

+1

如果沒有看到所有相關的源代碼,很難說出你的實現有什麼問題。你確定你正在將數據保存在另一個線程的上下文中嗎?保存是必需的(因爲合併操作將內存中的對象與商店對象進行比較),但是您在問題中沒有提及這一點。關於合併策略。當然,如果默認設置不符合您的需求,您可以在每個上下文中設置一個。再次,沒有額外的細節,很難說。 –

+0

這個答案是我在網上找到的唯一正確的解釋。 –

相關問題