Вопрос: как сделать изменения слияния Core Date, внесенные в один и тот же NSManagedObject
, в двух разных потоках?Потоки изменяют различные атрибуты, и любая комбинация этих атрибутов действительна.
Существует приложение с (как минимум) двумя потоками, потоком пользовательского интерфейса и фоновым потоком .Так называемый Document
является подклассом NSManagedObject
.Document
имеет три атрибута: attrA
, attrB
и attrC
.
Фоновый поток читает attrA
и записывает attrB
, например:
doc.attbB = md5(doc.attrA);
(на практике это более сложный и более трудоемкий процесс, но вы поняли).
Поток UI показывает все attrA
, attrB
и attrC
пользователю и позволяет пользователю изменять attrA
и attrC
.(И какое-то время значение 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
}
В общем случае это не сработает.
Сначала, что произойдет, если между этими строками будет сделано больше изменений:
[[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
после фонового потока , измененного attrB
, но до запуска __mergeChanges
.
Это классическое условие гонки.
Вопрос: как мне правильно внести изменения в Core Date для одного и того же NSManagedObject
в двух разных потоках?(Потоки изменяют различные атрибуты, и любая комбинация этих атрибутов действительна, но Базовые данные не знают об этом.)