Adakah cara untuk mengetahui kapan a UITableView
selesai meminta data dari sumber datanya?
Tak satu pun dari viewDidLoad
/ viewWillAppear
/ viewDidAppear
metode dari view controller ( UITableViewController
) terkait yang digunakan di sini, karena semuanya diaktifkan terlalu dini. Tak satu pun dari mereka (sepenuhnya dapat dimengerti) menjamin bahwa kueri ke sumber data telah selesai untuk saat ini (misalnya, hingga tampilan di-scroll).
Salah satu solusi yang saya temukan adalah untuk memanggil reloadData
di viewDidAppear
, karena, ketika reloadData
kembali, tampilan tabel yang dijamin selesai query sumber data sebanyak itu perlu untuk saat ini.
Namun, ini tampaknya agak buruk, karena saya berasumsi hal itu menyebabkan sumber data dimintai informasi yang sama dua kali (sekali secara otomatis, dan sekali karena reloadData
panggilan) saat pertama kali dimuat.
Alasan saya ingin melakukan ini semua adalah karena saya ingin mempertahankan posisi gulir UITableView
- tetapi sampai ke tingkat piksel, tidak hanya ke baris terdekat.
Saat memulihkan posisi gulir (menggunakan scrollRectToVisible:animated:
), saya memerlukan tampilan tabel untuk memiliki data yang cukup di dalamnya, atau scrollRectToVisible:animated:
pemanggilan metode tidak melakukan apa pun (yang terjadi jika Anda melakukan panggilan sendiri di salah satu viewDidLoad
, viewWillAppear
atau viewDidAppear
).
sumber
Jawaban:
Jawaban ini sepertinya tidak berfungsi lagi, karena beberapa perubahan yang dilakukan pada implementasi UITableView sejak jawabannya ditulis. Lihat komentar ini: Dapatkan pemberitahuan ketika UITableView selesai meminta data?
Aku sudah bermain dengan masalah ini selama beberapa hari dan berpikir bahwa subclassing
UITableView
'sreloadData
adalah pendekatan yang terbaik:reloadData
tidak berakhir sebelum tabel selesai memuat ulang datanya. Jadi, ketika yang keduaNSLog
diaktifkan, tampilan tabel sebenarnya telah selesai meminta data.Saya telah membuat subkelas
UITableView
untuk mengirim metode ke delegasi sebelum dan sesudahreloadData
. Ini bekerja seperti pesona.sumber
reloadData
segera kembali dan saya melihat "END reloadData" sebelum sel benar-benar dimuat ulang (yaitu sebelumUITableViewDataSource
metode dipanggil). Eksperimen saya menunjukkan kebalikan dari apa yang Anda katakan. Saya harus salah paham tentang apa yang Anda coba katakan.[super reloadData]
bekerja untuk saya:dispatch_async(dispatch_get_main_queue(), ^{NSLog(@"reload complete");});
. Ini pada dasarnya melompati blok yang diposting oleh tampilan tabelreloadData
.Saya memang memiliki skenario yang sama di aplikasi saya dan berpikir akan memposting jawaban saya kepada kalian karena jawaban lain yang disebutkan di sini tidak berfungsi untuk saya untuk iOS7 dan yang lebih baru
Akhirnya ini adalah satu-satunya hal yang berhasil bagi saya.
Pembaruan Swift:
Jadi bagaimana ini bekerja.
Pada dasarnya ketika Anda melakukan reload thread utama menjadi sibuk sehingga pada saat kami melakukan pengiriman thread async, blok akan menunggu sampai thread utama selesai. Jadi, setelah tampilan tabel dimuat sepenuhnya, utas utama akan selesai dan karenanya akan mengirimkan blok metode kami
Diuji di iOS7 dan iOS8 dan berfungsi dengan baik;)
Pembaruan untuk iOS9: Ini berfungsi dengan baik untuk iOS9 juga. Saya telah membuat proyek sampel di github sebagai POC. https://github.com/ipraba/TableReloadingNotifier
Saya melampirkan tangkapan layar tes saya di sini.
Lingkungan yang Diuji: Simulator iPhone6 iOS9 dari Xcode7
sumber
EDIT: Jawaban ini sebenarnya bukan solusi. Ini mungkin tampak berfungsi pada awalnya karena pemuatan ulang dapat terjadi cukup cepat, tetapi pada kenyataannya blok penyelesaian tidak selalu dipanggil setelah data selesai dimuat ulang - karena reloadData tidak memblokir. Anda mungkin harus mencari solusi yang lebih baik.
Untuk memperluas jawaban @Eric MORAND, mari kita masukkan blok penyelesaian. Siapa yang tidak suka satu blok?
dan...
Pemakaian:
sumber
dispatch_async(dispatch_get_main_queue(), ^{completionBlock();});
. Ini pada dasarnya melompati blok yang diposting oleh tampilan tabelreloadData
.reloadData hanya meminta data untuk sel yang terlihat. Dikatakan, untuk diberitahu ketika menentukan bagian dari tabel Anda dimuat, silakan kaitkan
tableView: willDisplayCell:
metode ini.sumber
Itulah solusi saya. 100% berfungsi dan digunakan di banyak proyek. Ini adalah subkelas UITableView sederhana.
Ini mirip dengan solusi Josh Brown dengan satu pengecualian. Tidak diperlukan penundaan dalam metode performSelector. Tidak peduli berapa lama
reloadData
.tableViewDidLoadData:
selalu aktif saattableView
selesai bertanyadataSource
cellForRowAtIndexPath
.Bahkan jika Anda tidak ingin membuat subkelas,
UITableView
Anda cukup memanggil[performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f]
dan pemilih Anda akan dipanggil tepat setelah tabel selesai dimuat ulang. Tetapi Anda harus memastikan bahwa pemilih hanya dipanggil sekali per panggilan kereloadData
:Nikmati. :)
sumber
performSelector
atau menjalankan di utas utama dengandispatch_asynch
tidak berfungsi di iOS 9 .Ini adalah jawaban untuk pertanyaan yang sedikit berbeda: Saya perlu tahu kapan
UITableView
juga selesai meneleponcellForRowAtIndexPath()
. Saya membuat subkelaslayoutSubviews()
(terima kasih @Eric MORAND) dan menambahkan panggilan balik delegasi:SDTableView.h:
SDTableView.m:
Pemakaian:
MyTableViewController.h:
MyTableViewController.m:
CATATAN: Karena ini adalah subclass
UITableView
yang sudah memiliki properti delegasi yang menunjukMyTableViewController
, tidak perlu menambahkan yang lain. "Delegasi @dynamic" memberi tahu kompilator untuk menggunakan properti ini. (Berikut tautan yang menjelaskan ini: http://farhadnoorzay.com/2012/01/20/objective-c-how-to-add-delegate-methods-in-a-subclass/ )The
UITableView
properti diMyTableViewController
harus diubah untuk menggunakan baruSDTableView
kelas. Ini dilakukan di Interface Builder Identity Inspector. Pilih bagianUITableView
dalamUITableViewController
dan setel "Kelas Kustom" keSDTableView
.sumber
Saya telah menemukan sesuatu yang mirip untuk mendapatkan notifikasi untuk perubahan
contentSize
dariTableView
. Saya pikir itu seharusnya berfungsi di sini juga karena contentSize juga berubah dengan memuat data.Coba ini:
Secara
viewDidLoad
tertulis,dan tambahkan metode ini ke viewController Anda:
Anda mungkin perlu sedikit modifikasi untuk memeriksa perubahan. Ini berhasil untuk saya.
Bersulang! :)
sumber
-viewWillAppear
dan hapus diri Anda dalam-viewWillDisapear
metode.Berikut solusi yang mungkin, meskipun ini adalah peretasan:
Di mana
-scrollTableView
metode Anda menggulir tampilan tabel dengan-scrollRectToVisible:animated:
. Dan, tentu saja, Anda dapat mengonfigurasi penundaan dalam kode di atas dari 0,3 menjadi apa pun yang tampaknya berhasil untuk Anda. Ya, ini sangat meretas, tetapi berfungsi untuk saya di iPhone 5 dan 4S saya ...sumber
Saya memiliki sesuatu yang serupa saya percaya. Saya menambahkan BOOL sebagai variabel instan yang memberi tahu saya jika offset telah dipulihkan dan memeriksanya
-viewWillAppear:
. Ketika belum dipulihkan, saya mengembalikannya dengan metode itu dan mengatur BOOL untuk menunjukkan bahwa saya memang memulihkan offset.Ini semacam peretasan dan mungkin bisa dilakukan lebih baik, tetapi ini berfungsi untuk saya saat ini.
sumber
-viewDidLoad
( di mana seharusnya terjadi tentu saja) tetapi itu hanya berfungsi ketika saya mengatur animasi offset. Dengan memindahkan pengaturan offset agar-viewWillAppear:
berfungsi, tetapi saya harus mempertahankan sebuah bendera untuk hanya mengaturnya sekali. Saya kira tampilan tabel memuat ulang datanya setelah ditambahkan ke tampilan, jadi itu sudah masuk-loadView
. Apakah Anda yakin data Anda tersedia saat dimuat? Atau sedang dimuat di utas terpisah atau sesuatu?Sepertinya Anda ingin memperbarui konten sel, tetapi tanpa lompatan tiba-tiba yang dapat menyertai penyisipan dan penghapusan sel.
Ada beberapa artikel tentang melakukan itu. Ini satu.
Saya sarankan menggunakan setContentOffset: animated: alih-alih scrollRectToVisible: animated: untuk pengaturan pixel-perfect dari tampilan scroll.
sumber
Anda dapat mencoba logika berikut:
Dan sebelum Anda memanggil reloadData, setel prevIndexPath ke nihil. Suka:
Saya menguji dengan NSLogs, dan logika ini tampaknya ok. Anda dapat menyesuaikan / meningkatkan sesuai kebutuhan.
sumber
akhirnya saya telah membuat kode saya berfungsi dengan ini -
ada beberapa hal yang perlu diperhatikan -
- (UITableViewCell *)MyTableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
"sumber
Anda dapat mengubah ukuran tampilan tabel Anda atau menyetelnya ukuran konten dalam metode ini ketika semua data dimuat:
sumber
Saya baru saja menjalankan pengatur waktu yang dijadwalkan berulang dan membatalkannya hanya ketika contentSize tabel lebih besar ketika tinggi tableHeaderView (berarti ada konten baris di tabel). Kode di C # (monotouch), tapi saya harap idenya jelas:
sumber
Tidak
UITableView
layoutSubviews
dipanggil tepat sebelum tampilan tabel menampilkan isinya? Saya perhatikan bahwa itu dipanggil setelah tampilan tabel selesai memuat datanya, mungkin Anda harus menyelidiki ke arah itu.sumber
Sejak iOS 6 dan seterusnya,
UITableview
metode delegasi memanggil:akan dijalankan setelah tabel Anda berhasil dimuat ulang. Anda dapat melakukan kustomisasi sesuai kebutuhan dalam metode ini.
sumber
Solusi terbaik yang saya temukan di Swift
sumber
Mengapa tidak diperpanjang saja?
gulir sampai akhir:
Tidak diuji dengan banyak data
sumber