Bir tablo görünümünün içeriğini yüklemeyi ne zaman tamamladığını bilmek için, öncelikle görünümlerin nasıl ekrana getirildiğiyle ilgili temel bir anlayışa sahip olmamız gerekir.
Bir uygulamanın yaşam döngüsünde 4 önemli an vardır:
- Uygulamaya bir etkinlik (dokunma, zamanlayıcı, gönderilen blok vb.)
- Uygulama etkinliği yönetir (bir kısıtlamayı değiştirir, bir animasyon başlatır, arka planı değiştirir vb.)
- Uygulama yeni görünüm hiyerarşisini hesaplar
- Uygulama görünüm hiyerarşisini oluşturuyor ve görüntülüyor
2 ve 3 kez tamamen ayrılmıştır. Neden ? Performans nedenlerinden ötürü, her değişiklik yapıldığında moment 3'ün tüm hesaplamalarını yapmak istemiyoruz.
Sanırım böyle bir dava ile karşı karşıyasınız:
tableView.reloadData()
tableView.visibleCells.count // wrong count oO
Burada yanlış olan ne?
Herhangi bir görünüm gibi, tablo görünümü de içeriğini tembel olarak yeniden yükler. Aslında, reloadData
birden çok kez ararsanız performans sorunları oluşturmaz. Tablo görünümü, yalnızca temsilci uygulamasına göre içerik boyutunu yeniden hesaplar ve hücrelerini yüklemek için 3 anını bekler. Bu zamana düzen geçişi denir.
Peki, düzen pasosuna nasıl girilir?
Düzen geçişi sırasında uygulama, görünüm hiyerarşisinin tüm karelerini hesaplar. Katılmak için, a ve eşdeğer yöntemleri bir görünüm denetleyicisi alt sınıfındaki özel yöntemleri layoutSubviews
, updateLayoutConstraints
vb. Geçersiz kılabilirsiniz UIView
.
Tablo görünümü tam olarak bunu yapar. Bu geçersiz kılar layoutSubviews
ve temsilci dayalı uygulama ekler veya kaldırır hücreleri. cellForRow
Yeni bir hücre eklemeden ve yerleştirmeden hemen önce, willDisplay
hemen sonra çağırır . Aradığınız Eğer reloadData
yoksa sadece hiyerarşiye tablo görünümü eklendi, tablolar görüntülemek gerektiği kadar hücreler bu tuş anda çerçevesini dolduracak şekilde ekler.
Tamam, ama şimdi, bir tablo görünümünün içeriğini yeniden yüklemeyi tamamladığını nasıl öğrenebilirim?
Şimdi bu soruyu yeniden ifade edebiliriz: bir tablo görünümünün alt görünümlerini düzenlemenin ne zaman bittiğini nasıl öğrenebiliriz?
• En kolay yol, tablo görünümünün düzenine girmektir:
class MyTableView: UITableView {
func layoutSubviews() {
super.layoutSubviews()
// the displayed cells are loaded
}
}
Bu yöntemin tablo görünümünün yaşam döngüsünde birçok kez çağrıldığına dikkat edin. Tablo görünümünün kaydırma ve dequeue davranışı nedeniyle, hücreler sık sık değiştirilir, çıkarılır ve eklenir. Ancak super.layoutSubviews()
, hücreler yüklendikten hemen sonra çalışır . Bu çözüm, willDisplay
son dizin yolunun olayını beklemeye eşdeğerdir . Bu olay, layoutSubviews
eklenen her hücre için tablo görünümünün yürütülmesi sırasında çağrılır .
• Başka bir yol, uygulama bir düzen geçişi tamamlandığında çağrı almaktır.
Belgelerde açıklandığı gibi, aşağıdakilerden birini kullanabilirsiniz UIView.animate(withDuration:completion)
:
tableView.reloadData()
UIView.animate(withDuration: 0) {
// layout done
}
Bu çözüm işe yarıyor ancak ekran, mizanpajın yapıldığı zaman ile bloğun çağrıldığı zaman arasında bir kez yenilenecek. Bu, DispatchMain.async
çözüme eşdeğerdir ancak belirtilmiştir.
• Alternatif olarak, tablo görünümünün düzenini zorlamayı tercih ederim
Herhangi bir görünümü alt görünüm çerçevelerini hemen hesaplamaya zorlamak için özel bir yöntem vardır layoutIfNeeded
:
tableView.reloadData()
table.layoutIfNeeded()
// layout done
Ancak dikkatli olun, sistem tarafından kullanılan tembel yüklemeyi kaldıracaktır. Bu yöntemleri tekrar tekrar çağırmak performans sorunları yaratabilir. Tablo görünümünün çerçevesi hesaplanmadan önce çağrılmadığından emin olun, aksi takdirde tablo görünümü yeniden yüklenir ve size bildirim gönderilmez.
Bence mükemmel bir çözüm yok. Alt sınıflar dertlere yol açabilir. Bir düzen geçişi üstten başlar ve alta gider, böylece tüm düzen tamamlandığında bildirim almak kolay değildir. Ve layoutIfNeeded()
performans sorunları vb oluşturabilir Ama o seçenekleri bilerek, kendi ihtiyacını uyacak bir alternatif de düşünmek gerekir.