Катастрофические отказы UITableView, если Источник данных Обновляется Во время Прокрутки

У меня есть приложение, где источник данных для UITableView обновляет фоновым потоком от удаленного сервера каждые 30 секунд.

Катастрофический отказ происходит, если пользователь прокручивает tableView или если tableView в процессе reloadTableView:. Причина катастрофического отказа состоит в том, что количество строк в таблице во время катастрофического отказа не соответствует количеству строк в то время запущенная перерисовка.

Другой катастрофический отказ происходит, когда требуемая ячейка TableView вне диапазона потому что между временем numberofTableViewCells: назван и время cellfForRowAtIndexPath назван, модель данных изменилась, и ячейка больше не там.

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

Как я блокирую tableView от прокрутки или перезагрузки, в то время как я обновляю tableViewDataSource? Какова лучшая практика для этого вида ситуации?

Спасибо.

24
задан TechZen 23 February 2010 в 14:00
поделиться

2 ответа

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

Однако с точки зрения дизайна пользовательского интерфейса активное обновление таблицы во время прокрутки пользователя дезориентирует пользователя. Пользователь подумает, что он находится в верхней / средней / нижней части таблицы, а затем внезапно окажется в нижней / верхней / средней части. Пользователь будет думать, что он просмотрел все данные в одном разделе таблицы, но на самом деле таблица добавит то, что им нужно увидеть. Например, если таблица представляет собой список имен в алфавитном порядке, пользователь проверяет все имена, начинающиеся с буквы «U», видит, что их нет, а затем переходит к проверке в другом месте таблицы. Между тем, таблица незаметно обновляет раздел «U» новыми именами, пока пользователь ищет в другом месте. Даже если пользователь понимает, что таблица динамически обновляется (что в большинстве случаев не обновляется), ему придется постоянно прокручивать, проверяя практически всю таблицу, чтобы увидеть, что изменилось.

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

Это сделает пользовательский интерфейс более понятным для пользователя и одновременно решит проблему сбоя.

Edit01:

Если вы не используете Core Data, чтобы реализовать живое и невидимое обновление таблицы. вам нужно будет заморозить в вызовах - tableView: numberOfRowsInSection или - numberOfSectionsInTableView: перед вызовом - tableView: cellForRowAtIndexPath: .

Так как - tableView: numberOfRowsInSection вызывается первым, я бы поместил туда вызов, чтобы сначала обновить, а затем заморозить модель данных. Таким образом, модель данных вернет правильное количество разделов и строк.

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

Кроме того, вам, вероятно, потребуется установить таймер, когда пользователь не перемещает стол. Таймер должен вызвать метод обновления, если таблица не используется активно, а затем он должен принудительно выполнить обновление.

Если вы используете Core Data, вы можете использовать NSFetchedResultController , и его методы-делегаты сообщат вам об изменении модели данных. Он должен возвращать правильную информацию о разделе и строке, обновленную в реальном времени. Управлять таким образом обновляющей таблицей довольно просто. Однако это не решит проблему ввода данных в модель так быстро, что модель будет меняться между вызовами методов. Вам все равно придется заморозить и / или замедлить модель.Однако таймер вам не понадобится.

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

Обновление:

Оглядываясь назад на этот ответ, я вижу, что я не упомянул [UITableView beginUpdates] , который заморозит конфигурацию таблицы при добавлении или удалении строк. Он соединен с [UITableView endUpdates] для включения изменений в пользовательский интерфейс.

18
ответ дан 29 November 2019 в 00:16
поделиться

Вызывать методы объектов GUI (например, UITableView) из фонового потока небезопасно.

Вам нужно сделать что-то вроде:

[ tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO]

См. uitableview-drawing-issues-when-reloaddata-is-is-called

5
ответ дан 29 November 2019 в 00:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: