问题:如何在两个不同的线程中对同一NSManagedObject
进行Core Date合并更改?线程会更改不同的属性,这些属性的任意组合都是有效的。
有一个应用程序(至少)有两个线程, UI线程和后台线程。
所谓的Document
是NSManagedObject
的子类。
Document
有三个属性,attrA
,attrB
和attrC
。
后台主题读取attrA
并写入attrB
,如:
doc.attbB = md5(doc.attrA);
(实际上,它更复杂,更耗时,但你明白了。)
UI线程向用户显示所有attrA
,attrB
和attrC
,并允许用户更改attrA
和{{1 }}。 (有些时候attrC
的值无效。)
我强调只有 UI线程写入attrB
,只有后台线程写入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
}
是的,我可以暂时替换,但这不是一般案例解决方案。如果这些变化反复发生,这可能是一个无限循环。
第二, UI线程也可能正试图保存一些东西。在其中一个类中,我看到了用于合并更改的代码,
[[doc managedObjectContext] refreshObject:doc mergeChanges:NO];
doc.attrB = tmp;
// more changes happen here!!!
BOOL saved = [context save:&error];
据我了解,#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
之后, UI线程可能会尝试保存attrA
和attrC
中的更改,但在attrB
运行之前。
这是一种典型的竞争条件。
问题:如何正确使核心日期合并在两个不同的线程中对同一__mergeChanges
进行合并? (线程更改了不同的属性,这些属性的任何组合都有效,但Core Data不知道。)
答案 0 :(得分:0)
我不是核心数据方面的专家,但我猜你可以使用synchronized指令:
// 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
}
如果任何其他线程正在执行其作用域,这应该会停止执行任何线程,请注意该实例应该是相同的,所以如果你不能访问该实例,你可以使用一个公共静态实例,这通常可以帮助我做这个技巧