Czy istnieje sposób, aby dowiedzieć się, kiedy UITableView
zakończyło się proszenie o dane ze swojego źródła danych?
Żadna z metod viewDidLoad
/ viewWillAppear
/ viewDidAppear
skojarzonego kontrolera widoku ( UITableViewController
) nie jest tutaj przydatna, ponieważ wszystkie uruchamiają się zbyt wcześnie. Żadne z nich (całkowicie zrozumiałe) nie gwarantuje, że zapytania do źródła danych na razie się zakończyły (np. Do przewinięcia widoku).
Jeden obejście znalazłem jest wywołanie reloadData
w viewDidAppear
, ponieważ, gdy reloadData
powróci, widok tabeli jest gwarancją zakończeniu kwerendy źródło danych tyle, ile potrzebuje na razie.
Wydaje się to jednak dość nieprzyjemne, ponieważ zakładam, że powoduje to dwukrotne pytanie źródła danych o te same informacje (raz automatycznie i raz z powodu reloadData
połączenia) podczas pierwszego ładowania.
Powodem, dla którego chcę to w ogóle zrobić, jest to, że chcę zachować pozycję przewijania UITableView
- ale aż do poziomu pikseli, a nie tylko do najbliższego wiersza.
Podczas przywracania pozycję przewijania (za pomocą scrollRectToVisible:animated:
), muszę widoku tabeli do już wystarczające dane w nim, albo też scrollRectToVisible:animated:
wywołanie metody nie robi nic (co jest to, co się dzieje, jeśli nawiązać połączenie na własną rękę w dowolnym viewDidLoad
, viewWillAppear
lub viewDidAppear
).
źródło
Odpowiedzi:
Wydaje się, że ta odpowiedź już nie działa, z powodu pewnych zmian wprowadzonych w implementacji UITableView od czasu napisania odpowiedzi. Zobacz ten komentarz: Chcesz otrzymywać powiadomienia, gdy UITableView zakończy proszenie o dane?
Grałem z tym problemem przez kilka dni i myślę, że podklasy
UITableView
„sreloadData
jest najlepszym rozwiązaniem:reloadData
nie kończy się przed zakończeniem ponownego ładowania danych w tabeli. Tak więc, gdy drugiNSLog
jest uruchamiany, widok tabeli w rzeczywistości zakończył żądanie danych.Podklasowałem,
UITableView
aby wysłać metody do delegata przed i poreloadData
. To działa jak urok.źródło
reloadData
wraca natychmiast i widzę „END reloadData”, zanim komórki zostaną faktycznie ponownie załadowane (tj. PrzedUITableViewDataSource
wywołaniem metod). Moje eksperymenty pokazują dokładne przeciwieństwo tego, co mówisz. Muszę źle zrozumieć, co próbujesz powiedzieć.[super reloadData]
prace dla mniedispatch_async(dispatch_get_main_queue(), ^{NSLog(@"reload complete");});
. Zasadniczo przeskakuje bloki, które są publikowane przez widok tabeli wreloadData
.Miałem taki sam scenariusz w mojej aplikacji i pomyślałem, że opublikuję moją odpowiedź dla was, ponieważ inne wymienione tutaj odpowiedzi nie działają dla mnie na iOS7 i później
W końcu to jedyna rzecz, która mi się sprawdziła.
Szybka aktualizacja:
Więc jak to działa.
Zasadniczo, gdy wykonujesz przeładowanie, główny wątek staje się zajęty, więc w tym czasie, gdy wykonujemy wysyłanie wątku asynchronicznego, blok będzie czekał, aż główny wątek zostanie zakończony. Tak więc po całkowitym załadowaniu widoku tabeli główny wątek zostanie zakończony, a więc wyśle nasz blok metody
Testowany w iOS7 i iOS8 i działa rewelacyjnie ;)
Aktualizacja dla iOS9: To po prostu działa dobrze, także iOS9. Stworzyłem przykładowy projekt na githubie jako POC. https://github.com/ipraba/TableReloadingNotifier
Załączam tutaj zrzut ekranu z mojego testu.
Testowane środowisko: symulator iPhone6 na iOS9 firmy Xcode7
źródło
EDYCJA: Ta odpowiedź w rzeczywistości nie jest rozwiązaniem. Prawdopodobnie wydaje się, że na początku działa, ponieważ ponowne ładowanie może nastąpić dość szybko, ale w rzeczywistości blok uzupełniania niekoniecznie jest wywoływany po całkowitym zakończeniu ponownego ładowania danych - ponieważ reloadData nie blokuje. Prawdopodobnie powinieneś poszukać lepszego rozwiązania.
Aby rozwinąć odpowiedź @Erica MORANDA, wstawmy blok uzupełniania. Kto nie lubi bloku?
i...
Stosowanie:
źródło
dispatch_async(dispatch_get_main_queue(), ^{completionBlock();});
. To w zasadzie przeskakuje bloki umieszczone w widoku tabeli wreloadData
.reloadData tylko prosząc o dane dla widocznych komórek. Mówi, że aby otrzymać powiadomienie o załadowaniu określonej części tabeli, podłącz
tableView: willDisplayCell:
metodę.źródło
To jest moje rozwiązanie. W 100% działa i jest używany w wielu projektach. To prosta podklasa UITableView.
Jest podobny do rozwiązania Josha Browna z jednym wyjątkiem. W metodzie performSelector nie jest potrzebne żadne opóźnienie. Nieważne, ile czasu
reloadData
to zajmie.tableViewDidLoadData:
zawsze strzela, gdytableView
kończy pytaćdataSource
cellForRowAtIndexPath
.Nawet jeśli nie chcesz podklasy
UITableView
, możesz po prostu zadzwonić,[performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f]
a Twój selektor zostanie wywołany zaraz po zakończeniu ładowania tabeli. Należy jednak upewnić się, że selector jest wywoływany tylko raz na wywołaniereloadData
:Cieszyć się. :)
źródło
performSelector
lub uruchamianie na głównym wątku zdispatch_asynch
nie działają na iOS 9 .To odpowiedź na nieco inne pytanie: musiałem wiedzieć, kiedy
UITableView
też skończyłem dzwonićcellForRowAtIndexPath()
. I podklasylayoutSubviews()
(dzięki @Eric Morand) i dodano wywołania zwrotnego delegata:SDTableView.h:
SDTableView.m:
Stosowanie:
MyTableViewController.h:
MyTableViewController.m:
UWAGI: Ponieważ jest to podklasa,
UITableView
która ma już właściwość delegata wskazującą,MyTableViewController
nie ma potrzeby dodawania kolejnej. „@Dynamic delegate” informuje kompilator, aby używał tej właściwości. (Oto link opisujący to: http://farhadnoorzay.com/2012/01/20/objective-c-how-to-add-delegate-methods-in-a-subclass/ )UITableView
MajątekMyTableViewController
musi zostać zmieniony, aby korzystać z nowejSDTableView
klasy. Odbywa się to w Inspektorze tożsamości programu Interface Builder. WybierzUITableView
wnętrzeUITableViewController
i ustaw jego „Custom Class” naSDTableView
.źródło
Znalazłem coś podobnego, aby dostać powiadomienie o zmianie
contentSize
odTableView
. Myślę, że to również powinno działać tutaj, ponieważ contentSize również zmienia się wraz z ładowaniem danych.Spróbuj tego:
Na
viewDidLoad
piśmiei dodaj tę metodę do swojego viewController:
Możesz potrzebować niewielkich modyfikacji w sprawdzaniu zmian. To jednak zadziałało dla mnie.
Twoje zdrowie! :)
źródło
-viewWillAppear
i usuń się z-viewWillDisapear
metody.Oto możliwe rozwiązanie, choć to hack:
Gdzie Twoja
-scrollTableView
metoda przewija widok tabeli za pomocą-scrollRectToVisible:animated:
. I, oczywiście, możesz skonfigurować opóźnienie w powyższym kodzie od 0.3 do tego, co wydaje się działać dla Ciebie. Tak, to absurdalne, ale działa na moim iPhonie 5 i 4S ...źródło
Wydaje mi się, że miałem coś podobnego. Dodałem zmienną BOOL jako instancji, która mówi mi, czy przesunięcie zostało przywrócone i sprawdź to
-viewWillAppear:
. Jeśli nie został przywrócony, przywracam go tą metodą i ustawiam BOOL, aby wskazał, że odzyskałem przesunięcie.To rodzaj hackowania i prawdopodobnie da się to zrobić lepiej, ale w tej chwili to działa.
źródło
-viewDidLoad
(tam, gdzie to oczywiście powinno się zdarzyć), ale to działało tylko wtedy, gdy ustawiłem przesunięcie jako animowane. Przesuwając ustawienie offsetu, aby-viewWillAppear:
działało, ale musiałem zachować flagę, aby ustawić ją tylko raz. Przypuszczam, że widok tabeli ponownie ładuje swoje dane po dodaniu do widoku, więc jest już w-loadView
. Czy na pewno masz dostępne dane podczas ładowania widoku? A może jest ładowany w osobnym wątku czy coś?Wygląda na to, że chcesz zaktualizować zawartość komórki, ale bez nagłych skoków, które mogą towarzyszyć wstawianiu i usuwaniu komórek.
Jest kilka artykułów na ten temat. To jest jeden.
Sugeruję użycie setContentOffset: animated: zamiast scrollRectToVisible: animated: dla perfekcyjnych ustawień widoku przewijania w pikselach.
źródło
Możesz wypróbować następującą logikę:
Zanim wywołasz reloadData, ustaw prevIndexPath na nil. Lubić:
Testowałem z NSLogs i ta logika wydaje się być w porządku. W razie potrzeby możesz dostosować / ulepszyć.
źródło
wreszcie sprawiłem, że mój kod działa z tym -
było kilka rzeczy, którymi należało się zająć -
- (UITableViewCell *)MyTableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
”źródło
Możesz zmienić rozmiar widoku tabeli lub ustawić rozmiar zawartości w tej metodzie po załadowaniu wszystkich danych:
źródło
Po prostu uruchamiam powtarzanie zaplanowanego timera i unieważniam go tylko wtedy, gdy contentSize tabeli jest większy, gdy wysokość tableHeaderView (oznacza, że w tabeli jest zawartość wierszy). Kod w C # (monotouch), ale mam nadzieję, że pomysł jest jasny:
źródło
Nie jest
UITableView
layoutSubviews
wywoływana tuż przed wyświetleniem zawartości w widoku tabeli? Zauważyłem, że jest on wywoływany, gdy widok tabeli zakończy ładowanie danych, może powinieneś zbadać w tym kierunku.źródło
Od wersji iOS 6
UITableview
metoda delegata o nazwie:zostanie wykonany po pomyślnym załadowaniu tabeli. W tej metodzie możesz dostosować ustawienia zgodnie z wymaganiami.
źródło
Najlepsze rozwiązanie jakie znalazłem w Swift
źródło
Dlaczego po prostu nie przedłużyć?
przewiń do końca:
Nie testowano z dużą ilością danych
źródło