2010-07-19 2 views
7

Я разрабатываю приложение iPhone с основными данными. Все пользовательские данные должны быть синхронизированы с нашими серверами. Для этого я создал подкласс NSOperation, который загружает новые данные из нашей веб-службы и создает соответствующие управляемые объекты. Чтобы поддерживать отношения между ними, каждый объект передается с помощью remoteID (который является первичным ключом базы данных реляционного сервера).Основные данные executeFetchRequest бросает NSGenericException (коллекция была мутирована при перечислении)

Скажем, есть два управляемых объекта: Отдел < - >> Сотрудник. Синхронизация работает следующим образом:

  1. Загрузить все отделы с сервера. Для каждого отдела: создайте объект отдела и установите его remoteID.

  2. Загрузить все сотрудники с сервера. Для каждого сотрудника: создайте объект Employee, выберите соответствующий отдел (remoteID) и назначьте его сотруднику.

Извлечение отдела приводит к следующему исключению:

*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFSet: 0x69c8a10> was mutated while being enumerated.<CFBasicHash 0x69c8a10 [0x2d6d380]>{type = mutable set, count = 1424, 
entries => <A list of all newly created entities> 

*** Call stack at first throw: 
0 CoreFoundation 0x02d04919 __exceptionPreprocess + 185 
1 libobjc.A.dylib 0x02e525de objc_exception_throw + 47 
2 CoreFoundation 0x02d043d9 __NSFastEnumerationMutationHandler + 377 
3 CoreData  0x026225d0 -[NSManagedObjectContext executeFetchRequest:error:] + 4400 
4 myApp   0x00059de4 +[AppFactory departmentWithRemoteID:inManagedObjectContext:] + 259 

Исключения не выброшено каждый раз. Перемещение кода в основной поток устраняет проблему. Я понятия не имею, что случилось. Я создал новый NSManagedObjectContaxt в потоке синхронизации и передал все управляемые объекты своим NSManagedObjectID.

Любые мысли?

ответ

1

В верхней части моей головы: есть ли «синхронизация», добавляющая новые объекты в коллекцию Департамента, итерации по ней на основной теме?

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

+0

для меня это может быть причиной такого рода проблем. Каков наилучший способ решения таких проблем, у вас есть идея @octy? –

+0

Приятно, хороший ответ на ваш вопрос был предоставлен в связанном обсуждении: http://stackoverflow.com/questions/3364769/iphone-nsfetchedresultscontroller-with-delegate-and-data-update-from-a-separate – octy

4

Ошибка «someCollection была мутирована при перечислении» вызвана изменением изменяемой коллекции, например, массива, словаря, набора и т. Д., В то время как перечислитель перешагивает его. Поскольку вы не можете перечислить движущуюся цель, это вызывает ошибку.

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

Работало вокруг этого, вы должны заморозить пользовательский интерфейс, когда вы объединяете изменения с фоновым потоком. Для табличных представлений выбранный контроллер результатов (NSFetchedResultsController) с правильно реализованными методами делегирования в контроллере tableview прекрасно справится с этой проблемой.

Важно, чтобы отправить beginUpdates в представление таблицы перед объединением новых данных. Это скажет, что эта базовая структура данных мутируется, поэтому она не будет пытаться перерисовать себя. Когда слияние завершено, отправьте endUpdates в представление таблицы, чтобы он отображал новую информацию.

+0

Я думал об этих проблемах, и поэтому я создал два NSManagedObjectContexts (один для основного потока и один для потока синхронизации). Разве это не действительное решение? Я также использую NSFetchedResultsController для своих табличных представлений. – Roland

+0

Да, но когда вы объединяете изменения, сделанные контекстами, они вызывают необходимость обновления, чтобы отразить изменения, сделанные в другом. Методы делегирования FRC позволяют сообщать пользовательскому интерфейсу о замораживании, пока эти изменения обрабатываются. Затем вы размораживаете пользовательский интерфейс и показываете обновления. Этот процесс обычно невидим для пользователя. – TechZen

+0

Приложение сработает, прежде чем слить изменения в основной поток. – Roland

13

У меня была такая же проблема ... Было решено, потому что я использовал managedObjectContext, который был создан в основном потоке в фоновом потоке. Решением было создать другой ManagedObjectContext в фоновом потоке и использовать регулярный persistentStoreCoordinator ... он работал отлично после этого!

0

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

Смежные вопросы