Как вы обрабатываете вставки разделов с помощью NSFetchedResultsController?

StackOverflow https://stackoverflow.com/questions/1561326

Вопрос

У меня есть NSFetchedResultsController в качестве источника данных, и я реализую NSFetchedResultsControllerDelegate в моем пользовательском UITableViewController.Я использую sectionNameKeyPath, чтобы разбить мой результирующий набор на несколько разделов.

В одном из моих методов я добавляю в контекст пару объектов, все из которых находятся в новом разделе.В тот момент, когда я сохраняю объекты, методы делегирования вызываются правильно.Порядок событий:

// -controllerWillChangeContent: fires
[self.tableView beginUpdates]; // I do this

// -controller:didChangeSection:atIndex:forChangeType: fires for section insert
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]];

// -controller:didChangeObject:atIndexPath:forChangeType:newIndexPath fires many times
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                withRowAnimation:UITavleViewRowAnimationFade]; // for each cell

// -controllerDidChangeContent: fires after all of the inserts
[self.tableView endUpdates];  // <--- Where things go terribly wrong!!!

При последнем вызове "endUpdates" приложение всегда выходит из строя с:

Serious application error.  Exception was caught during Core Data change processing:
[NSCFArray objectAtIndex:]: index (5) beyond bounds (1) with userInfo (null)

Похоже, что обновления таблицы каким-то образом не синхронизированы с данными NSFetchedResultsController, и все рушится.Я слежу за документами по NSFetchedResultsControllerDelegate, но это не работает.Как правильно это сделать?

Обновить: Я создал тестовый проект, в котором обнаружена эта ошибка.Вы можете скачать его по адресу: NSBoom.zip

Это было полезно?

Решение

Просматривая приложение, я отмечаю, что сначала вызывается didChangeSection, который вставляет целый раздел, а затем повторно вызывается didChangeObject.

Проблема в том, что в didChangeSection вы вставляете целый раздел, затем сразу после обновления табличного представления вы добавляете объекты в этот же раздел.По сути, это случай перекрывающихся обновлений...(не допускается даже в блоке begin / end обновления).

Если вы закомментируете вставку отдельного объекта, все это сработает:

 case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
            break;

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

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

Другие советы

У меня такая же проблема.Я обнаружил, что didChangeSection срабатывает дважды.Один раз, когда вы создаете объект для вставки, и один раз, когда вы фактически сохраняете его.На мой взгляд, он не должен вызывать didChangeSection до тех пор, пока не будет вызвано save .Или, по крайней мере, willChangeSection будет вызываться при создании объекта, а didChangeSection будет вызываться при его сохранении.

Теперь я изучаю метод наблюдателя NSManagedObjectContextDidSaveNotification.Это не является частью протокола NSFetchedResultsControllerDelegate, но вы можете зарегистрироваться для его получения.Возможно, это будет вызвано только тогда, когда я действительно вызову save, а не раньше.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top