Есть ли способ узнать, когда a UITableView
закончил запрашивать данные из своего источника данных?
Ни один из методов viewDidLoad
/ viewWillAppear
/ viewDidAppear
связанного контроллера представления ( UITableViewController
) здесь не используется, поскольку все они срабатывают слишком рано. Ни один из них (вполне понятно) не гарантирует, что запросы к источнику данных на данный момент завершены (например, пока представление не будет прокручено).
Один из способов я нашел позвонить reloadData
в viewDidAppear
, так как , когда reloadData
возвращается, как таблица будет гарантирован завершением запроса источника данных столько , сколько ему нужно , чтобы до поры до времени.
Однако это кажется довольно неприятным, поскольку я предполагаю, что это приводит к тому, что источник данных запрашивает одну и ту же информацию дважды (один раз автоматически и один раз из-за reloadData
вызова) при первой загрузке.
Причина, по которой я вообще хочу это сделать, заключается в том, что я хочу сохранить положение прокрутки UITableView
- но вплоть до уровня пикселей, а не только до ближайшей строки.
При восстановлении позиции прокрутки (с помощью scrollRectToVisible:animated:
) мне нужно, чтобы в табличном представлении уже было достаточно данных, иначе scrollRectToVisible:animated:
вызов метода ничего не делает (что происходит, если вы размещаете вызов самостоятельно в любом из viewDidLoad
, viewWillAppear
или viewDidAppear
).
источник
Ответы:
Этот ответ, похоже, больше не работает из-за некоторых изменений, внесенных в реализацию UITableView с момента написания ответа. См. Этот комментарий: Получать уведомление, когда UITableView завершил запрос данных?
Я играл с этой проблемой в течение нескольких дней , и думаю , что подклассы
UITableView
«sreloadData
это лучший подход:reloadData
не заканчивается до того, как таблица завершит перезагрузку данных. Итак, когдаNSLog
запускается второй , табличное представление фактически завершило запрос данных.Я создал подклассы
UITableView
для отправки методов делегату до и послеreloadData
. Работает как часы.источник
reloadData
немедленно, и я вижу «END reloadData» до того, как ячейки будут фактически перезагружены (т.е. до вызоваUITableViewDataSource
методов). Мои эксперименты демонстрируют прямо противоположное тому, что вы говорите. Я должен неправильно понять, что вы пытаетесь сказать.[super reloadData]
работает для меня:dispatch_async(dispatch_get_main_queue(), ^{NSLog(@"reload complete");});
. Это в основном перепрыгивает через блоки, которые публикуются в табличном представленииreloadData
.У меня был такой же сценарий в моем приложении, и я подумал, что опубликую свой ответ вам, ребята, поскольку другие ответы, упомянутые здесь, не работают для меня для iOS7 и более поздних версий.
Наконец, это единственное, что у меня получилось.
Быстрое обновление:
Итак, как это работает.
В основном, когда вы выполняете перезагрузку, основной поток становится занятым, поэтому в то время, когда мы выполняем асинхронный поток отправки, блок будет ждать завершения основного потока. Итак, как только tableview будет полностью загружен, основной поток будет завершен, и поэтому он отправит наш блок метода
Протестировано на iOS7 и iOS8, отлично работает;)
Обновление для iOS9: отлично работает и iOS9. Я создал образец проекта в github как POC. https://github.com/ipraba/TableReloadingNotifier
Прилагаю сюда скриншот своего теста.
Протестированная среда: симулятор iOS9 iPhone6 от Xcode7
источник
РЕДАКТИРОВАТЬ: этот ответ на самом деле не является решением. Вероятно, сначала это работает, потому что перезагрузка может происходить довольно быстро, но на самом деле блок завершения не обязательно вызывается после того, как данные полностью завершили перезагрузку, потому что reloadData не блокируется. Возможно, вам стоит поискать лучшее решение.
Чтобы расширить ответ @Eric MORAND, давайте добавим блок завершения. Кому не нравится блок?
и...
Использование:
источник
dispatch_async(dispatch_get_main_queue(), ^{completionBlock();});
. Это в основном перепрыгивает блоки, размещенные в табличном представленииreloadData
.reloadData просто запрашивает данные для видимых ячеек. Говорит, чтобы получить уведомление, когда указанная часть вашей таблицы загружена, подключите
tableView: willDisplayCell:
метод.источник
Это мое решение. 100% работает и используется во многих проектах. Это простой подкласс UITableView.
Это похоже на решение Джоша Брауна, за одним исключением. В методе performSelector задержка не требуется. Независимо от того, сколько времени
reloadData
займет.tableViewDidLoadData:
всегда срабатывает, когдаtableView
заканчивает спрашиватьdataSource
cellForRowAtIndexPath
.Даже если вы не хотите создавать подклассы,
UITableView
вы можете просто вызвать,[performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f]
и ваш селектор будет вызван сразу после завершения перезагрузки таблицы. Но вы должны убедиться, что селектор вызывается только один раз за вызовreloadData
:Наслаждаться. :)
источник
performSelector
или выполнение в основном потокеdispatch_asynch
не работают на iOS 9 .Это ответ на несколько другой вопрос: мне нужно было знать, когда я
UITableView
тоже закончил звонитьcellForRowAtIndexPath()
. ЯlayoutSubviews()
выделил подклассы (спасибо @Eric MORAND) и добавил обратный вызов делегата:SDTableView.h:
SDTableView.m:
Использование:
MyTableViewController.h:
MyTableViewController.m:
ПРИМЕЧАНИЯ: Поскольку это подкласс, у
UITableView
которого уже есть свойство делегата, указывающее наMyTableViewController
то, нет необходимости добавлять еще один. «@Dynamic delegate» указывает компилятору использовать это свойство. (Вот ссылка с описанием этого: http://farhadnoorzay.com/2012/01/20/objective-c-how-to-add-delegate-methods-in-a-subclass/ )UITableView
Свойство вMyTableViewController
должно быть изменено , чтобы использовать новыйSDTableView
класс. Это делается в Инспекторе удостоверений Interface Builder. ВыделитеUITableView
внутреннюю частьUITableViewController
и установите для «Custom Class» значениеSDTableView
.источник
Я нашел что - то подобное , чтобы получить уведомление о изменении
contentSize
вTableView
. Я думаю, что это должно работать и здесь, поскольку contentSize также изменяется при загрузке данных.Попробуй это:
В
viewDidLoad
письменной форме,и добавьте этот метод в свой viewController:
Вам могут потребоваться небольшие изменения в проверке изменений. Хотя это сработало для меня.
Ура! :)
источник
-viewWillAppear
и удалите себя из-viewWillDisapear
метода.Вот возможное решение, хотя это и есть взлом:
Где ваш
-scrollTableView
метод прокручивает представление таблицы с помощью-scrollRectToVisible:animated:
. И, конечно же, вы можете настроить задержку в приведенном выше коде от 0,3 до того, что вам подходит. Да, это смехотворно взломано, но у меня работает на моих iPhone 5 и 4S ...источник
Думаю, у меня было нечто подобное. Я добавил BOOL в качестве переменной экземпляра, которая сообщает мне, было ли восстановлено смещение, и проверяет это
-viewWillAppear:
. Когда он не был восстановлен, я восстанавливаю его этим методом и устанавливаю BOOL, чтобы указать, что я действительно восстановил смещение.Это своего рода хакерство, и его, вероятно, можно было бы сделать лучше, но сейчас это работает для меня.
источник
-viewDidLoad
(где это, конечно, должно было произойти), но это сработало только тогда, когда я установил смещение анимированным. Перемещение настройки смещения на-viewWillAppear:
это сработало, но мне пришлось поддерживать флаг, чтобы установить его только один раз. Я полагаю, что табличное представление перезагружает свои данные после добавления в представление, так что это уже есть-loadView
. Вы уверены, что ваши данные доступны при загрузке просмотра? Или он загружается в отдельном потоке, что ли?Похоже, вы хотите обновить содержимое ячеек, но без внезапных скачков, которые могут сопровождать вставки и удаления ячеек.
Об этом есть несколько статей. Это один.
Я предлагаю использовать setContentOffset: animated: вместо scrollRectToVisible: animated: для точных настроек просмотра прокрутки.
источник
Вы можете попробовать следующую логику:
И прежде чем вызывать reloadData, установите для prevIndexPath значение nil. Подобно:
Я тестировал с NSLogs, и эта логика кажется нормальной. Вы можете настроить / улучшить по мере необходимости.
источник
наконец, я заставил свой код работать с этим -
было несколько вещей, о которых нужно было позаботиться -
- (UITableViewCell *)MyTableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
"источник
Вы можете изменить размер представления таблицы или установить размер содержимого в этом методе, когда все данные загружены:
источник
Я просто запускаю повторяющийся запланированный таймер и делаю его недействительным только тогда, когда contentSize таблицы больше, когда высота tableHeaderView (означает, что в таблице есть содержимое строк). Код на C # (монотач), но, надеюсь, идея понятна:
источник
Не
UITableView
layoutSubviews
вызывается непосредственно перед отображением содержимого таблицы? Я заметил, что он вызывается после того, как представление таблицы завершит загрузку своих данных, возможно, вам стоит исследовать в этом направлении.источник
Начиная с iOS 6,
UITableview
метод делегата вызывал:будет выполняться после успешной перезагрузки вашей таблицы. Вы можете выполнить настройку по мере необходимости в этом методе.
источник
Лучшее решение, которое я нашел в Swift
источник
Почему просто не продлить?
прокрутите до конца:
Не тестировалось с большим количеством данных
источник