问题:如何使“核心日期”合并在两个不同线程中对相同NSManagedObject
所做的更改?线程更改不同的属性,并且这些属性的任何组合都是有效的。
有一个具有(至少)两个线程的应用程序,UI线程和后台线程。
所谓的Document
是NSManagedObject
的子类。Document
具有三个属性,attrA
,attrB
和attrC
。
后台线程读取attrA
并写入attrB
,例如:
doc.attbB = md5(doc.attrA);
(在实践中,它更复杂,更耗时,但是您可以理解)。
UI线程向用户显示所有
attrA
,attrB
和attrC
,并允许用户更改attrA
和attrC
。 (并且在某些时候attrB
的值无效。)我强调指出,只有UI线程才写入
attrA
,只有后台线程才写入attrB
。现在,用户在完成
attrC
的计算之前更改attrB
。后台线程尝试保存
attrB
并得到一个错误。我现在所做的是:
if(!saved) {
// I did try to check that it's *that* kind of error,
// but that's iOS5-specific, while I need 4.3
// (comments on error type checking in 4.3 are welcome).
// Anyway, finally it was this:
id tmp = doc.attrB;
[[doc managedObjectContext] refreshObject:doc mergeChanges:NO];
doc.attrB = tmp;
BOOL saved = [context save:&error];
// NSLog if it still failed
}
在一般情况下,这是行不通的。
首先,如果在这些行之间进行更多更改会发生什么:
[[doc managedObjectContext] refreshObject:doc mergeChanges:NO];
doc.attrB = tmp;
// more changes happen here!!!
BOOL saved = [context save:&error];
是的,我可以暂时替换一下,但这不是一般情况下的解决方案。如果更改重复发生,则可能是一个无休止的循环。
第二,UI线程也可能正在尝试保存某些内容。在其中一个类中,我看到了旨在合并更改的代码,
#pragma mark Changes Propagation
- (void)__contextDidSave:(NSNotification*)notification
{
[parent performSelectorOnMainThread:@selector(__mergeChanges:) withObject:notification waitUntilDone:NO];
}
- (void)__mergeChanges:(NSNotification*)notification
{
[objectContext mergeChangesFromContextDidSaveNotification:notification];
if (parent) {
[parent __mergeChanges:notification];
}
}
据我了解,
__mergeChanges
将在正确的线程上运行,但不会立即运行;在后台线程更改attrA
之后但在运行attrC
之前,UI线程可能会尝试保存attrB
和__mergeChanges
中的更改。这是经典的比赛条件。
问题:如何正确 使Core Date合并在两个不同线程中对相同
NSManagedObject
所做的更改? (线程更改了不同的属性,并且这些属性的任何组合都是有效的,但是Core Data不知道。) 最佳答案
我不是核心数据专家,但是我猜您可以使用synced指令:
// UI Thread
@synchronized(AN_INSTANCE_OF_ANY_OBJECT) {
// your first thread's code goes here
}
// Background Thread
@synchronized(THE_SAME_INSTANCE_OF_THE_OBJECT) {
// your second thread's code goes here
}
如果任何其他线程正在执行其作用域,则这应该停止任何线程的执行,请注意该实例应该相同,因此,如果无法访问该实例,则可以使用公共(public)静态实例,这通常可以帮助我完成此操作。