Я пытаюсь прокрутить до конца UITableView после того, как это сделано, выполняя [self.tableView reloadData]
У меня изначально было
[self.tableView reloadData]
NSIndexPath* indexPath = [NSIndexPath indexPathForRow: ([self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1) inSection: ([self.tableView numberOfSections]-1)];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
Но потом я прочитал, что reloadData является асинхронным, поэтому прокрутка не происходит self.tableView
, [self.tableView numberOfSections]
и [self.tableView numberOfRowsinSection
все они равны 0.
Спасибо!
Что странно, что я использую:
[self.tableView reloadData];
NSLog(@"Number of Sections %d", [self.tableView numberOfSections]);
NSLog(@"Number of Rows %d", [self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1);
В консоли возвращает Sections = 1, Row = -1;
Когда я делаю точно такие же NSLogs, cellForRowAtIndexPath
я получаю Sections = 1 и Row = 8; (8 верно)
Ответы:
Перезагрузка происходит во время следующего прохода макета, что обычно происходит, когда вы возвращаете управление в цикл выполнения (например, после нажатия кнопки или любого другого возврата).
Таким образом, один из способов запустить что-то после перезагрузки табличного представления - просто заставить табличное представление немедленно выполнить компоновку:
Другой способ - запланировать запуск кода после компоновки, используя
dispatch_async
:ОБНОВИТЬ
После дальнейшего изучения я обнаружил, что табличное представление отправляет
tableView:numberOfSections:
иtableView:numberOfRowsInSection:
в свой источник данных, прежде чем вернуться изreloadData
. Если делегат реализуетtableView:heightForRowAtIndexPath:
, табличное представление также отправляет это (для каждой строки) перед возвратом изreloadData
.Однако табличное представление не отправляет
tableView:cellForRowAtIndexPath:
илиtableView:headerViewForSection
до фазы макета, что происходит по умолчанию, когда вы возвращаете управление в цикл выполнения.Я также обнаружил, что в крошечной тестовой программе код в вашем вопросе правильно прокручивается до нижней части табличного представления, без каких- либо специальных действий (например, отправка
layoutIfNeeded
или использованиеdispatch_async
).источник
dispatch_async(dispatch_get_main_queue())
метод не гарантирует работу. Я вижу недетерминированное поведение с ним, в котором иногда система завершает layoutSubviews и рендеринг ячейки до блока завершения, а иногда и после. Я выложу ответ, который работал для меня ниже.dispatch_async(dispatch_get_main_queue())
не всегда работает. Видя случайные результаты здесь.NSRunLoop
. Цикл выполнения имеет разные фазы, и вы можете запланировать обратный вызов для определенной фазы (используя aCFRunLoopObserver
). UIKit планирует размещение на более позднем этапе, после того, как ваш обработчик события вернется.Swift:
Objective-C:
источник
tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
метод и вставив в свое переопределение все, что я хотел, чтобы уведомить о завершении перезагрузки.Начиная с Xcode 8.2.1, iOS 10 и swift 3,
Вы можете
tableView.reloadData()
легко определить конец с помощью блока CATransaction:Вышеприведенное также работает для определения конца reloadData () UICollectionView и reloadAllComponents UIPickerView.
источник
beginUpdates
иendUpdates
вызовах.setCompletionBlock
моиnumberOfSections
шоу 2 ... пока все хорошо. И все же, если внутриsetCompletionBlock
я делаюtableView.headerView(forSection: 1)
это возвращаетсяnil
!!! следовательно, я думаю, что этот блок либо происходит до перезагрузки, либо фиксирует что-то раньше, либо я делаю что-то не так. К вашему сведению, я попробовал ответить Тайлеру, и это сработало! @ Толстякdispatch_async(dispatch_get_main_queue())
Метод выше не гарантирует работу . Я вижу недетерминированное поведение с ним, в котором иногда система завершает layoutSubviews и рендеринг ячейки до блока завершения, а иногда и после.Вот решение, которое работает на 100% для меня, на iOS 10. Требуется возможность создания экземпляра UITableView или UICollectionView в качестве пользовательского подкласса. Вот решение UICollectionView, но оно точно такое же для UITableView:
CustomCollectionView.h:
CustomCollectionView.m:
Пример использования:
Смотрите здесь для Swift версию этого ответа
источник
layoutSubviews
нем должно быть установлено значение, такnil
как последующие вызовыlayoutSubviews
, не обязательно вызванные вызовомreloadData
, приведут к выполнению блока, поскольку удерживается сильная ссылка, что не является желаемым поведением.reloadDataCompletionBlock
создать массив блоков и перебрать их при выполнении, а затем очистить массив.У меня были те же проблемы, что и у Тайлера Шиффера.
Я реализовал его решение в Swift, и оно решило мои проблемы.
Swift 3.0:
Свифт 2:
Пример использования:
источник
if let
, сказав,reloadDataCompletionBlock?()
что будет называть, если не ноль Tyself.reloadDataCompletionBlock? { completion() }
должен былself.reloadDataCompletionBlock?()
И
UICollectionView
версия, основанная на ответе kolaworld:https://stackoverflow.com/a/43162226/1452758
Необходимо тестирование. Пока работает на iOS 9.2, Xcode 9.2 beta 2, с прокруткой collectionView к индексу, как закрытие.
Использование:
источник
Кажется, что люди все еще читают этот вопрос и ответы. В связи с этим, я редактирую свой ответ, чтобы удалить слово Синхронный, которое на самом деле не имеет к этому отношения.
When [tableView reloadData]
возвращает, внутренние структуры данных за tableView были обновлены. Поэтому, когда метод завершится, вы можете спокойно перейти к нижней части. Я подтвердил это в моем собственном приложении. Широко принятый ответ @ rob-mayoff, хотя и запутанный в терминологии, подтверждает то же самое в своем последнем обновлении.Если вы
tableView
не прокручиваете страницу до конца, у вас может быть проблема с другим кодом, который вы не опубликовали. Возможно, вы изменяете данные после завершения прокрутки и не перезагружаете и / или не прокручиваете до конца?Добавьте некоторые записи, как показано ниже, чтобы убедиться, что данные таблицы верны
reloadData
. У меня есть следующий код в примере приложения, и он отлично работает.источник
reloadData
не синхронно. Раньше было - смотрите этот ответ: stackoverflow.com/a/16071589/193896reloadData
возврата.reloadData
. Используйте мой тестовый сценарий вviewWillAppear
accept дляscrollToRowAtIndexPath:
строки b / c, которая не имеет смысла, еслиtableView
она не отображается. Вы увидите, чтоreloadData
обновили данные, кэшированные вtableView
экземпляре, и этоreloadData
синхронно. Если вы ссылаетесь на другиеtableView
методы делегата, вызываемые приtableView
разметке, они не будут вызваны, еслиtableView
не отображается. Если я неправильно понимаю ваш сценарий, пожалуйста, объясните.Я использую этот трюк, уверен, я уже разместил его в дубликате этого вопроса:
источник
На самом деле этот решил мою проблему:
источник
Попробуй так будет работать
Я выполню, когда таблица полностью загружена
Другое решение - вы можете создать подкласс UITableView
источник
В итоге я использовал вариант решения Шона:
Создайте пользовательский класс UITableView с делегатом:
Затем в моем коде я использую
Также убедитесь, что вы установили табличное представление на CustomTableView в конструкторе интерфейса:
источник
В Swift 3.0 + мы можем создать расширение для
UITableView
сescaped Closure
подобным ниже:И используйте его как ниже, где вы хотите:
надеюсь, это кому-нибудь поможет. ура!
источник
подробности
Решение
использование
Полный образец
Полученные результаты
источник
Просто чтобы предложить другой подход, основанный на идее завершения, являющейся «последней видимой» ячейкой для отправки
cellForRow
.Одна из возможных проблем: Если
reloadData()
завершено до того, какlastIndexPathToDisplay
было установлено, «последняя видимая» ячейка будет отображаться до того, какlastIndexPathToDisplay
было установлено, и завершение не будет вызываться (и будет в состоянии «ожидания»):Если мы повернем вспять, мы можем получить завершение, вызванное прокруткой раньше
reloadData()
.источник
Попробуй это:
Цвет tableView будет изменен с черного на зеленый только после завершения
reloadData()
функции.источник
Вы можете использовать функцию executeBatchUpdates в uitableview
Вот как вы можете достичь
источник
Создание многоразового расширения CATransaction:
Теперь создаем расширение UITableView, которое будет использовать метод расширения CATransaction:
Использование:
источник
Вы можете использовать его для выполнения каких-либо действий после перезагрузки данных:
источник
Попробуйте установить задержки:
источник