2

我創建了一個NSOperationQueue所有關於一個表的inserting/updating/deleting/searching的操作。我使用MagicalRecord進行核心數據操作。但是我在同步時遇到了一些問題。一個簡單的例子如下。NSOperationQueue,CoreData和MagicalRecord同步問題

例如,一個名爲person的表和一個名爲like的人內部的列。當用戶點擊一個按鈕時,like將增加1。我不喜歡它

[SameBackgroundQueue addOperationWithBlock:^{ 
    User *user = [User MR_findFirstWithPredicate:some_predicate]; 
    user.like += 1; 
    NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread]; 
    [localContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { 
     [SameBackgroundQueue addOperationWithBlock:^{ 
      [self syncWithServer];//This can take time 
    }]; 
}]; 

然而,如果用戶點擊快,等不正確的,因爲MR_findFirstWithPredicate可以得到髒記錄。問題源於NSOperationQueue可以僱員不同的線程,而MR_findFirstWithPredicate使用當前線程的上下文。因此,它可能會嘗試從不同的NSManagedObjectContext獲取用戶,因此它將獲取髒數據。

當然,如果我們使用mainQueue,我們不會有任何問題。但是,我怎樣才能使用後臺線程,並確保我沒有骯髒的記錄問題。似乎整個問題都可以解決,如果我運行在一個特定的線程而不是用戶NSOperationQueue。我應該使用GCD嗎?


在我以前的項目中,我使用

[self createManagedObjectContextWithParent:self.mainQueueManagedObjectContext andConcurrencyType:NSPrivateQueueConcurrencyType];

[managedObjectContext save:&error]; 
if (managedObjectContext.parentContext) { 
    [managedObjectContext.parentContext performBlock:^{ 
     NSError *parentError = nil; 
     [managedObjectContext.parentContext save:&parentError]; 
    }]; 
} 

我知道有WWDC視頻談論的NSManagedObjectContext和併發上下文等,但如果我使用這個,我不能使用MagicRecord。

任何建議將不勝感激。


其實我找到一個更有效的方法來做到這一點。如果我做錯了,請糾正我。

我實際上創建了一個共同的單身人士上下文[NSManagedObjectContext MR_context]爲User OperationQueue共享。所以即使所有的線程訪問相同的上下文,他們也不會弄髒數據。

仍然會有毛刺,例如,如果兩個線程正在改變同一個上下文中的同一個對象會發生什麼。這通常是非常罕見的情況,但我會看到它是如何發生的。我可能會將最大併發線程設置爲1,以避免出現這種情況。我不確定它是否會降低性能。將明天更新進度。

回答

2

爲了避免這種競爭情況你可能會限制你的NSOperationQueue以一次一個操作設置:

[TheSameQueue setMaxConcurrentOperationCount:1]; 

使之成爲串行執行隊列。

你也可以使用GCD創建一個串行隊列(但是你將有一個更難的時間取消和設置操作的依賴關係)。

(在後臺都使用GCD)

我會在不同的隊列,所以它不會妨礙本地用戶體驗執行服務器同步(您也可以使主線程上的局部變化,和只有在後臺同步)

爲當地的更改不會跟蹤和需要同步的目的是服務器沒有保留的應用啓動之間(保存到存儲成功,但同步到服務器您同步到服務器可能會出現問題中斷/失敗等)。

+0

嗨,這可能是一個解決方案。但它會限制後臺隊列的性能。感謝您解決同步問題。我正在盡全力,如跟蹤狀態,並比較修改的時間等。 –

+0

現在,用戶同步功能也使用UserQueue。也許我應該使用另一個隊列UserSyncQueue,以便User CoreData只使用一個併發線程,但UserSyncQueue可以同時佔用多個線程。 –

3

我建議改變你的操作塊到更多的東西是這樣的:

[TheSameQueue addOperationWithBlock:^{ 
    NSManagedObjectContext *localContext = [NSManagedObjectContext MR_context]; 

    User *user = [User MR_findFirstWithPredicate:some_predicate inContext:localContext]; 
    user.like += 1; 

    [localContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { 
     [self syncWithServer];//This can take time 
    }]; 
}]; 

你是在默認情況下,你可以想到的主線程上下文做的所有後臺操作。一般來說,這將工作99%的時間,但會導致隨機死鎖和崩潰。此外,MR_contextForCurrentThread已棄用,因爲它也會導致隊列出現問題,即對線程使用錯誤的上下文。

+0

感謝您的回答。根據我的理解,MR_context是MR_defaultContext的一個子元素,也就是默認情況下的mainQueueContext。 –

+0

感謝您發佈答案。 –

+0

所以在技術上MR_context是一個背景上下文,而不是mainQueue上下文:) –