Ответ 1
Короткий ответ заключается в том, что вам необходимо буферизовать данные в вашей модели данных и обновлять таблицу только новыми данными, когда таблица не прокручивается. Это необходимо сделать в модели данных, потому что делегат datasource не знает, что находится внутри модели данных или что изменилось.
Однако, с точки зрения дизайна пользовательского интерфейса, наличие активного обновления таблицы во время прокрутки пользователя будет дезориентировать пользователя. Пользователь будет думать, что они находятся в верхней/средней/нижней части таблицы, а затем внезапно оказываются в нижней/верхней/средней. Пользователь будет думать, что они просмотрели все данные в одном разделе таблицы, но в действительности таблица добавит что-то, что им нужно было увидеть. Например, если таблица представляет собой список алфавитных имен, пользователь проверяет все имена, смотрящие на "U", видит, что их нет, а затем идет, чтобы проверить где-то еще в таблице. Между тем, таблица невидимо обновляет раздел "U" со свежими именами, пока пользователь смотрит в другое место. Даже если пользователь понимает, что таблица динамически обновляется (чего больше всего нет), им придется постоянно прокручивать, проверяя практически всю таблицу, чтобы увидеть, что изменилось.
Лучший дизайн пользовательского интерфейса - дать пользователю возможность обновлять. Поместите в панель кнопку "Обновить" или "Новые данные", а затем установите ее, когда появятся новые данные. После нажатия кнопки заморозить таблицу, обновить и только затем возобновить взаимодействие пользователя. Также неплохо было бы визуально обозначить добавленные строки.
Это сделает пользовательский интерфейс более понятным для пользователя и одновременно устранит вашу проблему.
Edit01:
Если вы не используете Core Data, чтобы реализовать живое и невидимое обновление таблицы. вам необходимо заморозить в вызовах – tableView:numberOfRowsInSection
или – numberOfSectionsInTableView:
до вызова – tableView:cellForRowAtIndexPath:
.
Так как – tableView:numberOfRowsInSection
вызывается первым, я бы поместил там вызов для первого обновления и затем заморозил вашу модель данных. Таким образом, модель данных вернет правильное количество разделов и строк.
Я предполагаю, что вам придется разделить вашу модель данных на два раздела, один из которых будет буферизовать входящие данные, а другой - упорядочить данные для отображения. Ваш метод обновления должен переместить все завершенные буферизованные данные в раздел данных дисплея.
Кроме того, вам, вероятно, потребуется установить таймер, когда пользователь не перемещает таблицу. Таймер должен вызывать метод обновления, если таблица не подвергается активной манипуляции, а затем она должна принудительно обновлять.
Если вы используете Core Data, вы можете использовать NSFetchedResultController
, и методы делегирования сообщают вам, когда модель данных изменится. Он должен вернуть информацию в соответствующем разделе и строке, обновленную в реальном времени. Это довольно легко управлять таблицей обновления таким образом. Однако он не справится с проблемой ввода данных в модель так быстро, что модель изменится между вызовами метода. Вам все равно придется замораживать и/или замедлять работу модели. Однако вам не нужен таймер.
Core Data - ваш лучший вариант, но даже это будет сложно реализовать, потому что вы пытаетесь что-то сделать против зерна пользовательского интерфейса, и поэтому API не поддерживает его.
Обновление:
Оглядываясь назад на этот ответ, я вижу, что я забыл упомянуть [UITableView beginUpdates]
, который заморозит конфигурацию таблицы, когда строки будут добавлены или удалены. Он сопряжен с [UITableView endUpdates]
, чтобы включить изменения в пользовательский интерфейс.