Чтобы узнать, когда представление таблицы завершает загрузку своего содержимого, нам сначала нужно иметь общее представление о том, как представления выводятся на экран.
В жизненном цикле приложения есть 4 ключевых момента:
- Приложение получает событие (касание, таймер, отправка блока и т. Д.)
- Приложение обрабатывает событие (изменяет ограничение, запускает анимацию, меняет фон и т. Д.)
- Приложение вычисляет новую иерархию представлений
- Приложение визуализирует иерархию представлений и отображает ее
2 и 3 раза полностью разделены. Зачем ? По соображениям производительности мы не хотим выполнять все вычисления момента 3 каждый раз, когда выполняется модификация.
Итак, я думаю, вы столкнулись с таким случаем:
tableView.reloadData()
tableView.visibleCells.count
Что здесь не так?
Как и любое представление, представление таблицы лениво перезагружает свое содержимое. На самом деле, если вы вызовете reloadData
несколько раз, это не вызовет проблем с производительностью. Представление таблицы только пересчитывает размер своего содержимого на основе реализации делегата и ожидает момента 3 для загрузки своих ячеек. Это время называется проходом по макету.
Хорошо, как попасть на проход верстки?
Во время этапа макета приложение вычисляет все кадры иерархии представления. Чтобы принять участие, вы можете переопределить выделенные методы layoutSubviews
и updateLayoutConstraints
т. Д. В a UIView
и эквивалентные методы в подклассе контроллера представления.
Это именно то, что делает табличное представление. Он переопределяет layoutSubviews
и в зависимости от реализации вашего делегата добавляет или удаляет ячейки. Он вызывается cellForRow
прямо перед добавлением и размещением новой ячейки willDisplay
сразу после. Если вы вызвали reloadData
или просто добавили представление таблицы в иерархию, представление таблицы добавляет столько ячеек, сколько необходимо, чтобы заполнить его фрейм в этот ключевой момент.
Хорошо, но теперь, как узнать, когда представление таблиц завершило перезагрузку своего содержимого?
Теперь мы можем перефразировать этот вопрос: как узнать, когда табличное представление закончило выкладывать свои подвиды?
• Самый простой способ - попасть в макет представления таблицы:
class MyTableView: UITableView {
func layoutSubviews() {
super.layoutSubviews()
}
}
Обратите внимание, что этот метод вызывается много раз в жизненном цикле табличного представления. Из-за прокрутки и поведения вывода из очереди в табличном представлении ячейки часто изменяются, удаляются и добавляются. Но он работает сразу после super.layoutSubviews()
загрузки ячеек. Это решение эквивалентно ожиданию willDisplay
события последнего пути индекса. Это событие вызывается во время выполнения layoutSubviews
табличного представления для каждой добавленной ячейки.
• Другой способ - получить вызов, когда приложение завершит этап макета.
Как описано в документации , вы можете использовать один из следующих вариантов UIView.animate(withDuration:completion)
:
tableView.reloadData()
UIView.animate(withDuration: 0) {
}
Это решение работает, но экран обновится один раз между временем создания макета и моментом вызова блока. Это эквивалентно DispatchMain.async
решению, но указано.
• В качестве альтернативы я бы предпочел принудительно настроить макет таблицы.
Существует специальный метод, позволяющий заставить любое представление немедленно вычислять его кадры подпредставления layoutIfNeeded
:
tableView.reloadData()
table.layoutIfNeeded()
Однако будьте осторожны, это устранит ленивую загрузку, используемую системой. Повторный вызов этих методов может вызвать проблемы с производительностью. Убедитесь, что они не будут вызваны до того, как будет вычислен фрейм табличного представления, иначе табличное представление будет загружено снова, и вы не получите уведомления.
Думаю, идеального решения не существует. Создание подклассов могло привести к неприятностям. Проход макета начинается сверху и идет вниз, поэтому получить уведомление о завершении макета непросто. И layoutIfNeeded()
может создать проблемы с производительностью и т. Д. Но зная эти варианты, вы должны уметь думать об одной альтернативе, которая будет соответствовать вашим потребностям.