"Нет канала базы данных"

У меня есть приложение, которое подключается к Интернету и хранит данные в базе данных SQL. Я тестировал iOS4, он работает полностью, как должен. Однако, когда я обновляюсь до новой версии, я получаю исключение NSInternalInconsistencyException, и в этом причина:

'_ getOpenChannel - NSSQLCore 0x951a640: канал базы данных недоступен

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

Может ли кто-нибудь помочь мне найти и правильно диагностировать мою проблему?

Ответ 1

Я нашел что-то для этого:

Я получил ошибку (среди некоторых других, казалось бы, случайным образом), когда я обращался к отношениям управляемых объектов в другом потоке, чем тот, в котором был создан управляемый контекст. Были некоторые изменения в отношении одновременный доступ к управляемым объектам в iOS5 (см. здесь http://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-CoreData/_index.html#//apple_ref/doc/uid/TP40010637) - и хотя в документе указано, что поведение по умолчанию должно быть как pre-iOS5, очевидно, это не верно, мой код действительно работал без проблем в iOS4.2.

В настоящее время моим обходным решением было сделать все привязки к отношениям в основном потоке, сохранить данные в массиве и получить доступ к данным, которые мне нужны в другом потоке через этот массив. По крайней мере, больше ошибок. Это не "хорошее" решение, я полагаю, поскольку я должен (и будет) изменять способ доступа к управляемым объектам одновременно, но я не собираюсь менять это в спешке.

Ответ 2

Этот тип по умолчанию concurrency для NSManagedObjectContext равен NSConfinementConcurrencyType, что означает, что он может использоваться только одним потоком. Из документации:

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

Вместо этого вы можете создать контекст управляемого объекта, который поддерживается частной очереди для многопоточного использования:

[[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]

Чтобы использовать контекст управляемого объекта из другого потока, используйте performBlock: (asyncronous) или performBlockAndWait: (синхронно), например

__block NSArray *results;
[[self managedObjectContext] performBlockAndWait:^{
    results = [[self managedObjectContext] executeFetchRequest:request error:&error];
}];
// do something with results

В документации говорится, что вам не нужно использовать API-интерфейс блока из потока, создавшего контекст управляемого объекта.

Другим вариантом является создание отдельных контекстов управляемых объектов для каждого потока.

Подробнее см. примечания к выпуску iOS 5.