UITableView падает, если источник данных обновляется во время прокрутки - PullRequest
24 голосов
/ 23 февраля 2010

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

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

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

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

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

Спасибо.

Ответы [ 2 ]

18 голосов
/ 23 февраля 2010

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

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

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

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

Edit01:

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

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

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

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

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

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

Обновление:

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

5 голосов
/ 23 февраля 2010

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

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

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

См. uitableview-СОСТАВЛЕНИЕ проблемы, когда-reloaddata-это-называется

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...