проблема синхронизации reloadData - PullRequest
0 голосов
/ 19 апреля 2011

Итак, вот моя проблема. На домашней странице моего приложения у меня есть простой UITableView, который может содержать максимум 3 раздела, 2 раздела максимум по 3 элемента в каждом, а третий раздел может содержать максимум 6 элементов.

Каждый раздел имеет заголовок, связанный с.

Фактический контент поступает из Интернета, я делаю запрос, сервер отправляет данные, я анализирую ответ с помощью NSXMLParser, создаю массивы для хранения данных для каждого раздела (3 массива), а также создаю другой массив для хранения ссылки на разделы мне придется отображать.

Затем, в конце, я вызываю [myTableView reloadData], чтобы обновить содержимое и перерисовать таблицу. Пользователи также имеют возможность самостоятельно обновлять контент. Для этого я использую механизм Pull-to-Refresh, как и приложение Facebook.

Обновление контента с использованием pull-to-refresh также заканчивается вызовом [myTableView reloadData]. Я испытываю неприятный сбой, когда обновляю содержимое, и таблица должна изменить свое расположение (например, таблица в настоящее время содержит все 3 раздела, а после перезагрузки данных будет отображаться только один раздел).

Я использовал отладчик, чтобы отследить проблему. Вот что я нашел:

  1. Пользователь сносит всю таблицу примерно на 50 пикселей, а затем отпускает
  2. Начинается анимация, которая поднимает таблицу вверх, чтобы вместить представление 320x50 с отображением сообщения «Загрузка» + UIActivityIndicatorView, анимированного в верхней части таблицы
  3. Обновление запущено, я делаю новый запрос веб-сервиса в фоновой задаче, получаю новые данные, анализирую, обновляю массивы и, наконец, в основном потоке выполняю reloadData
  4. Тем временем, пока обновление выполняет все, что я заметил, UITableView STILL отправляет сообщения делегата:
    • Tableview: viewForHeaderInSection:
    • Tableview: cellForRowAtIndexPath:

Я полагаю, что это происходит из-за анимации pull-to-refresh, которая «перемещает» таблицу вверх и выявляет новые ячейки / заголовки, вызывая, таким образом, выше.

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

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

  • numberOfSectionsInTableView:
  • tableView: numberOfRowsInSection:

когда-либо получит шанс правильно обновить новую структуру для обновленных массивов.

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

Спасибо за чтение!

ПОСЛЕДНЕЕ РЕДАКТИРОВАНИЕ :

Я нашел, где была проблема. Мой механизм pull-to-refresh использует обратный вызов stopLoading, который выглядит следующим образом:

- (void)stopLoading 

{ isLoading = NO;

// Hide the header
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDidStopSelector:@selector(stopLoadingComplete:finished:context:)];
self.myTableView.contentInset = UIEdgeInsetsZero;
[refreshArrow layer].transform = CATransform3DMakeRotation(M_PI * 2, 0, 0, 1);
[UIView commitAnimations];

}

В какой-то момент я сбросил contentInset для моей таблицы, установив его в UIEdgeInsetsZero. Это и тот факт, что после фонового обновления, возвращающегося в основном потоке, я вызывал stopLoading ПЕРЕД reloadData - вызвал неправильные обратные вызовы делегата в неправильный момент.

Так что это была проблема синхронизации между изменением contentInset моей таблицы и reloadData.

1 Ответ

0 голосов
/ 19 апреля 2011

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

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

...