Para saber quando uma visualização de tabela termina de carregar seu conteúdo, primeiro precisamos ter um entendimento básico de como as visualizações são colocadas na tela.
No ciclo de vida de um aplicativo, existem quatro momentos principais:
- O aplicativo recebe um evento (toque, cronômetro, bloco despachado etc.)
- O aplicativo lida com o evento (modifica uma restrição, inicia uma animação, altera o plano de fundo etc.)
- O aplicativo calcula a nova hierarquia de visualizações
- O aplicativo processa a hierarquia de visualizações e exibe-a
Os tempos 2 e 3 são totalmente separados. Por quê ? Por razões de desempenho, não queremos realizar todos os cálculos do momento 3 cada vez que uma modificação é feita.
Então, acho que você está enfrentando um caso como este:
tableView.reloadData()
tableView.visibleCells.count // wrong count oO
O que há de errado aqui?
Como qualquer visualização, uma visualização de tabela recarrega seu conteúdo lentamente. Na verdade, se você ligar reloadData
várias vezes, isso não criará problemas de desempenho. A exibição da tabela apenas recalcula o tamanho do conteúdo com base na implementação delegada e aguarda o momento 3 para carregar suas células. Esse tempo é chamado de passe de layout.
Ok, como entrar no passe de layout?
Durante a aprovação do layout, o aplicativo calcula todos os quadros da hierarquia de visualizações. Para se envolver, você pode substituir os métodos dedicados layoutSubviews
, updateLayoutConstraints
etc em a UIView
e os métodos equivalentes em uma subclasse do controlador de exibição.
É exatamente isso que uma exibição de tabela faz. Ele substitui layoutSubviews
e, com base na implementação delegada, adiciona ou remove células. Ele chama cellForRow
logo antes de adicionar e colocar uma nova célula, willDisplay
logo depois. Se você chamou reloadData
ou acabou de adicionar a exibição de tabela à hierarquia, a exibição de tabelas adiciona quantas células forem necessárias para preencher seu quadro nesse momento chave.
Tudo bem, mas agora, como saber quando uma exibição de tabelas terminou de recarregar seu conteúdo?
Agora podemos reformular esta pergunta: como saber quando uma exibição de tabela terminou de exibir suas subvisões?
• A maneira mais fácil é entrar no layout da exibição da tabela:
class MyTableView: UITableView {
func layoutSubviews() {
super.layoutSubviews()
// the displayed cells are loaded
}
}
Observe que esse método é chamado várias vezes no ciclo de vida da visualização da tabela. Devido ao comportamento de rolagem e desenfileiramento da exibição de tabela, as células são modificadas, removidas e adicionadas frequentemente. Mas funciona logo após o super.layoutSubviews()
carregamento das células. Esta solução é equivalente a aguardar o willDisplay
evento do último caminho do índice. Este evento é chamado durante a execução delayoutSubviews
exibição da tabela para cada célula adicionada.
• Outra maneira é ser chamado quando o aplicativo termina um passe de layout.
Conforme descrito na documentação , você pode usar uma opção do UIView.animate(withDuration:completion)
:
tableView.reloadData()
UIView.animate(withDuration: 0) {
// layout done
}
Essa solução funciona, mas a tela é atualizada uma vez entre o momento em que o layout é concluído e o horário em que o bloco é chamado. Isso é equivalente à DispatchMain.async
solução, mas especificado.
• Como alternativa, eu preferiria forçar o layout da exibição da tabela
Existe um método dedicado para forçar qualquer visualização a calcular imediatamente seus quadros de subvisão layoutIfNeeded
:
tableView.reloadData()
table.layoutIfNeeded()
// layout done
Tenha cuidado, no entanto, isso removerá o carregamento lento usado pelo sistema. Chamar esses métodos repetidamente pode criar problemas de desempenho. Verifique se eles não serão chamados antes que o quadro da visualização da tabela seja computado, caso contrário, a visualização da tabela será carregada novamente e você não será notificado.
Eu acho que não há solução perfeita. Classes de subclassificação podem levar a trubles. Um passe de layout começa de cima e vai para baixo, para que não seja fácil ser notificado quando todo o layout estiver pronto. E layoutIfNeeded()
pode criar problemas de desempenho, etc. Mas conhecendo essas opções, você deve pensar em uma alternativa que atenda às suas necessidades.