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