Проблема сброса / обновления NSManagedObjectContext и NSArrayController

У меня возникли проблемы с отображением в моем пользовательском интерфейсе внешних изменений (внесенных другим процессом) в хранилище данных sqlite.

У меня есть довольно стандартное представление таблицы / NSArrayController на основе основных данных. Мое приложение получает уведомление о том, что в данные были внесены внешние изменения, после чего я делаю

[managedObjectContext reset]; // brute force, but data set is small

Проблема в том, что при этом удаляются все данные из таблицы. ArraysObjects контроллера массива также пуст. Я думал, что последующий

[arrayController fetch:nil];

может помочь, но это не так. Выполнение запроса на выборку в managedObjectContext показывает, что данные присутствуют и обновляются, поэтому managedObjectContext знает об изменениях.

Есть какие-нибудь подсказки, как "восстановиться" после сброса? Или, возможно, подход сброса вообще неверен, и в этом случае есть лучший способ загрузить внешние изменения?


person Adrian    schedule 13.01.2010    source источник
comment
Когда вы говорите «другой процесс», это внешний по отношению к приложению или другой поток внутри приложения?   -  person Marcus S. Zarra    schedule 13.01.2010
comment
Я имею в виду процесс в обычном смысле, так что да - он внешний по отношению к приложению, а не просто отдельный поток внутри приложения.   -  person Adrian    schedule 13.01.2010


Ответы (2)


Я не думаю, что два процесса должны работать в одной и той же базе данных Core Data. Вероятно, лучше позволить одному процессу действовать как сервер, который владеет (и открывает) базу данных, а другой может посылать ему команды для внесения изменений. Я не думаю, что Core Data когда-либо предназначалась для поддержки нескольких процессов, обращающихся к одной и той же базе данных.

person Stefan Arentz    schedule 22.01.2010
comment
Это правильно. Core Data управляет атомарными хранилищами и не может использоваться как база данных клиент-сервер. - person Rob Keniger; 22.01.2010
comment
Да, теперь, когда я провел рефакторинг, чтобы один и тот же процесс - и фактически один и тот же поток - всегда работал с базой данных, все работает хорошо. Однако жаль, поскольку базовая база данных Sqlite обрабатывает многопроцессорный доступ и манипуляции. Кажется разумным ожидать, что Core Data сможет обновлять данные из базы данных при получении соответствующего уведомления. - person Adrian; 29.05.2010

Итак, я играл с этой точной ситуацией, и я не буду противоречить первому ответу - вы, вероятно, не должны этого делать, и если вам нужно, может быть, iCloud работает. Не используйте этот код. Я предоставляю его, чтобы помочь другим добраться до момента, когда они смогут обнаружить все проблемы, которые я не исправил, и двигаться дальше.

Тем не менее, вы можете сделать то, что искал исходный вопрос - заставить контроллер перезагрузиться с диска:

// Tear down bindings and context, create new context & rebind
[self.watcherAC unbind:@"managedObjectContext"];
[self saveAction:self]; // Optional, dependent on NSMergePolicy, etc
self.managedObjectContext = [[NSManagedObjectContext alloc] init];
self.managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
[self.managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
[self.watcherAC bind:@"managedObjectContext" toObject:self withKeyPath:@"managedObjectContext" options:nil];

// Force controller to refetch and rearrange
NSError* error;
[self.watcherAC fetchWithRequest:nil merge:NO error:&error];  // Immediate fetch
[self.watcherAC prepareContent];
[self.watcherAC rearrangeObjects];

Это обновляет содержимое tableView из хранилища на диске. (TableView привязан к контроллеру массива watcherAC)

Я обнаружил, что выборка: происходит не сразу - это выполняется в следующий раз через цикл выполнения приложения. Итак, чтобы выборка / перестановка выполнялись в правильном порядке, вам необходимо использовать fetchWithRequest:

Я не уверен, что нужен prepareContent:, хотя он, возможно, помог устранить ошибки в содержимом контроллера.

Мне не удалось заставить его восстановить выбор tableView, хотя это может быть потому, что я делаю это в вызове делегата tableview, поэтому выбор представления не синхронизируется с выбором контроллера, независимо от того, какие взломы я пробую. Может быть это сработает для кого-то, но я предлагаю попытаться выяснить, как не выделять новый MOC, если ваше представление имеет привязки к нему.

person stevesliva    schedule 02.04.2014