Я создаю NSOperationQueue
для всех операций, касающихся inserting/updating/deleting/searching
одной единственной таблицы. Я использую MagicalRecord
для работы с данными Core. Но у меня проблема с синхронизацией. Упрощенный пример выглядит следующим образом.
Например. Таблица с именем person
и столбец внутри человека с именем like
. Когда пользователь нажимает кнопку, like
увеличивается на единицу. Я делаю это как
[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. Таким образом, даже все потоки обращаются к одному и тому же контексту, они не получат грязные данные.
По-прежнему будут сбои, например, что, если два потока изменяют один и тот же объект одного и того же контекста. Обычно это очень редкий случай, но я посмотрю, как все пойдет. Я могу установить максимальное количество одновременных потоков равным единице, просто чтобы избежать ситуации. Я не уверен, снизит ли это производительность. Буду обновлять прогресс завтра.