В моем приложении iPad есть UITableView, заполненный из фида. Как и большинство читателей RSS, он отображает список ссылок на сообщения в блоге в обратном хронологическом порядке, с их заголовками и резюме каждого сообщения. Канал обновляется часто и довольно большой, около 500 сообщений. Я использую libxml2 push parsing для эффективной загрузки и анализа фида в подклассе NSOperation, создания объектов ввода и обновления базы данных по мере того, как я иду. Но тогда мне нужно обновить UITableView с изменениями.
До сих пор приложение обновляло UITableView для каждого анализируемого сообщения, поскольку оно анализируется. Парсер выполняет селектор основного потока для выполнения этой работы. Но это приводит к некоторому серьезному отставанию в течение нескольких секунд, если необходимо обновить много ячеек. Я могу смягчить это, запустив обновление таблицы в фоновом потоке, но кажется, что это не очень хорошая идея. Итак, теперь я пытаюсь выяснить, как повысить эффективность таблицы в основном потоке.
Я мог бы просто называть reloadData
, когда все сообщения были проанализированы, но это не очень удобно: нет анимации, указывающей на то, что что-то изменилось, просто вспышка и новые данные. Я бы предпочел, чтобы анимация показала, что новые сообщения добавлены, а старые сообщения удалены. Существующие сообщения, которые не удаляются из фида, должны быть сдвинуты вниз по таблице новыми сообщениями, появляющимися вверху.
Я знаю, что это возможно. Byline, чтобы дать один пример, делает красивую работу. Каждый пост добавляется или удаляется из UITableView по одному разу без пробелов, отображающих фон таблицы. Все, не создавая пользовательский интерфейс, в наименьшей степени не реагируют. Как это делается?
Моя последняя попытка - обновить таблицу только после того, как все сообщения были проанализированы (парсер довольно быстрый, поэтому он не сильно задерживается). Затем он загружает существующие записи в NSDictionary, сопоставляя свои идентификаторы с их индексами в массиве, используемом в качестве источника данных таблицы. Затем он выполняет итерацию по каждому объекту в вновь обработанном массиве сообщений, добавляя NSIndexPath для каждого из массивов, которые затем передаются в -insertRowsAtIndexPaths:withRowAnimation:
, -deleteRowsAtIndexPaths:withRowAnimation:
и -reloadRowsAtIndexPaths:withRowAnimation:
в зависимости от необходимости вставлять, удалять, перемещать или обновлять ячейки, Для 500 сообщений это занимает около 4 секунд для обновления, при этом пользовательский интерфейс полностью не отвечает. Это время используется почти исключительно для анимированных обновлений UITableView; итерация по двум массивам сообщений занимает очень мало времени.
Затем я изменил его так, чтобы они обновлялись без анимации, и у меня есть отдельные массивы для вставки/удаления/перезагрузки с анимацией только для позиций строк, соответствующих видимым в настоящее время строкам. Это лучше, но пробелы появляются, когда сообщения удаляются, а новые добавляются.
Извините, это так долго, но вот результат:
Как я могу обновить UITableView, нажав на новые ячейки, другие оттолкнулись, а другие переместились из одной позиции в другую, до 500 ячеек в UITableView (6-8 видимы за один раз) и каждая анимация происходит последовательно, все время, пока пользовательский интерфейс остается полностью отзывчивым?