Sztuczki poprawiające wydajność przewijania iPhone'a UITableView?

89

Mam uitableview, który ładuje dość duże obrazy w każdej komórce, a wysokości komórek różnią się w zależności od rozmiaru obrazu. Wydajność przewijania jest przyzwoita, ale czasami może być nierówna.

Znalazłem te wskazówki, które znalazłem na blogu FieryRobot:

glassy-scrolling-with-uitableview

more-glassy-scrolling-with-uitableview

Czy ktoś ma jakieś wskazówki dotyczące poprawy wydajności przewijania uitableview?

Jonasza
źródło
Jeśli potrzebujesz buforować wysokości komórek (które mogą być kosztowne do obliczenia i są często używane), podałem przykład. Używaj tego tylko wtedy, gdy jest to odpowiednie dla twojej aplikacji. stackoverflow.com/questions/1371223/…
Paul de Lange

Odpowiedzi:

156
  1. Buforuj wysokość wierszy (widok tabeli może często żądać tego)
  2. Utwórz najmniej używaną pamięć podręczną dla obrazów używanych w tabeli (i unieważnij wszystkie nieaktywne wpisy, gdy pojawi się ostrzeżenie dotyczące pamięci)
  3. Narysuj wszystko w UITableViewCell, drawRect:jeśli to możliwe, unikaj podglądów podrzędnych za wszelką cenę (lub jeśli potrzebujesz standardowej funkcji dostępności, widoku zawartości drawRect:)
  4. Ustaw UITableViewCellnieprzezroczystą warstwę (to samo dotyczy widoku zawartości, jeśli taki masz)
  5. Użyj funkcji reusableCellIdentifier zgodnie z zaleceniami w UITableViewprzykładach / dokumentacji
  6. Unikaj gradientów / skomplikowanych efektów graficznych, które nie są wstępnie zapieczętowane w UIImages
rpetrich
źródło
5
Ponadto pobrane obrazy powinny zostać przeskalowane do rozmiaru imageView przed wyświetleniem w komórce!
Zoltán Matók,
4
Do tej odpowiedzi chciałbym dodać jedno z moich doświadczeń z ostatnich kilku lat - posiadanie przezroczystych komórek prawdopodobnie nigdy nie jest przyczyną złej wydajności przewijania. Mamy aplikację z BARDZO skomplikowanymi komórkami (ponad 20 podglądów) i wszystko jest przezroczyste, aby pokazać tło. Przy odpowiedniej optymalizacji przezroczystość nie ma znaczenia nawet w 3GS. W rzeczywistości najbardziej spowolniło to ładowanie stalówki, zanim było wystarczająco dużo komórek do usunięcia z kolejki w widoku tabeli. Jeśli używasz widoków podrzędnych, po prostu upewnij się, że masz wydajne hierarchie i nie musisz używać drawRect.
Accatyyc
@Accatyyc, wygląda na to, że mam ten sam problem. Istnieje małe opóźnienie, gdy nie ma wystarczającej liczby komórek do usunięcia z kolejki, gdy usuwa się z kolejki 3-4 komórki, przewijanie jest płynne. Czy istnieje sposób, aby wstępnie załadować komórki, aby były komórki do usunięcia z kolejki i nie ładować plików NIB podczas przewijania?
Tiois,
@Tiois Pewnie, że jest. Musisz użyć starego sposobu usuwania z kolejki komórek (nie rejestruj klas / końcówek, ale utwórz je, jeśli dequeueCellWithIdentifier: zwraca nil). W ten sposób możesz utworzyć zestaw komórek, zanim jeszcze istnieje widok tabeli, na przykład tworząc wcześniej 20 z nich. Następnie zamiast tworzyć nowe w cellForRowAtIndexPath:, najpierw wyciągasz je z własnej pamięci podręcznej, aż będzie pusta.
Accatyyc,
Używam UICollectionView i mam ten sam problem. W moim niestandardowym pliku stalówki komórki. Używam kilku widoków podrzędnych, w tym UIwebView i UIImageView w pionowym widoku UIstackView. kiedy przewijam listę, ponownie używane komórki potrzebują dużo czasu, aby dostosować ich rozmiar, a przewijanie wygląda na bardzo nierówne.
Mansuu ....
40
  1. Jeśli tworzysz podklasy UITableViewCell, nie używaj końcówki, zamiast tego napisz ją w kodzie. To znacznie szybsze niż ładowanie plików Nib.
  2. Jeśli używasz obrazów, pamiętaj, aby je buforować, aby nie trzeba było ładować z pliku więcej niż raz dla każdego (jeśli masz pamięć - zdziwiłbyś się, ile miejsca zajmują obrazy).
  3. Spraw, aby jak najwięcej elementów było nieprzezroczystych. Podobnie staraj się nie używać obrazów z przezroczystością.
Shaggy Frog
źródło
3
nie martw się ... to były trolle. świetna odpowiedź!
Steav
79
Głosy negatywne były prawdopodobnie spowodowane tym, że „unikaj stalówek” to zła rada dotycząca poprawy wydajności. Jeśli ponownie używasz komórek, komórki nie są w ogóle odtwarzane ze stalówek podczas przewijania.
Steven Fisher,
6
Stalówki są równoważne pod względem szybkości lub nieco szybsze na podstawie badań Cocoa with Love. cocoawithlove.com/2010/03/…
MaxGabriel
@Steven Fisher używający Nib może działać wolniej, gdy na przykład alokuje tabelę i usuwa komórki z niej - podczas szybkiego przewijania.
Sound Blaster
3
Korzystanie z NIB może być wolniejsze podczas konstruowania komórki . Jeśli korzystasz z recyklingu komórek, przydzielonych jest tylko tyle komórek, aby wypełnić ekran; powiedzmy maksymalnie 10. Podczas przewijania komórki nie są tworzone. Są po prostu ponownie wykorzystywane , a nie zwalniane i ponownie przydzielane. I oczywiście nie ma żadnych kosztów związanych z cofnięciem przydziału. Więc nie, to nie jest poprawne.
Steven Fisher
34

Deweloper stojący za Tweetie obszernie o tym napisał i ma kod, który pokazuje, jak to zostało zrobione dla tej aplikacji. Zasadniczo opowiada się za jednym niestandardowym widokiem na komórkę tabeli i rysowaniem go ręcznie (zamiast między innymi przeglądać za pomocą Interface Builder).

fast-scrolling-in-tweetie-with-uitableview

Ponadto firma Apple zaktualizowała własny przykładowy kod dla TableView w swoich samouczkach TableViewSuite (może w odpowiedzi na to?)

TableViewSuite

beno
źródło
1
To świetne rozwiązanie. Jestem po prostu ciekawy, jak dodać UIButton do cellView? Czy jest rysowany w metodzie drawRect?
Sukitha Udugamasooriya
1
@beno, Twój link wydaje się uszkodzony (pierwszy). Czy masz szansę położyć ręce na oryginalnym artykule?
apouche
3
Oryginalny artykuł można przeczytać tutaj: web.archive.org/web/20100922230053/http://blog.atebits.com/2008/…
jverdi
dodany link do archiwum internetowego, ponieważ oryginalna wersja nie istnieje
Ralph Willgoss
1

Najlepszy zabójca wydajności w przewijaniu UITableView polega na rysowaniu cieni na dowolnej warstwie widoku komórki, więc jeśli wydajność przewijania ma znaczenie, nie rób cieni, chyba że w zasadzie nie spowalnia to głównego wątku.

pomyślałem, że trzeba to powiedzieć, ponieważ żadna z zaakceptowanych odpowiedzi nie wspomina o cieniach i warstwach. : +)

JackyJohnson
źródło
6
jeśli problemem są cienie, dodaj te dwie linie kodu i wszystko działa idealnie self.layer.shouldRasterize = YES; self.layer.rasterizationScale = UIScreen.mainScreen.scale;
Pedro Romão
0

Każdy problem z UITableViewwydajnością przewijania można rozwiązać za pomocą technik opisanych już w innych odpowiedziach. Jednak często powolne działanie jest spowodowane przez coś z natury błędnego lub powtarzającego się.

Fakt, że UITableViewponownie wykorzystuje komórki oraz fakt, że każda komórka może potrzebować własnego obrazu - razem komplikuje rozwiązanie. Z ogólnego sposobu rozwiązania tego problemu podsumowuję rzeczy, którymi należy się zająć:

  1. Załaduj dane do źródła danych - z REST / bazy danych. Ten krok należy wykonać w tle, ewentualnie przy użyciu dispatch_async wraz z kolejką GCD.
  2. Twórz i inicjalizuj odpowiednie obiekty modelu danych i umieszczaj je w tablicy
  3. [tableView reloaddata]
  4. Wewnątrz cellForRowAtIndexPathumieść kod, który ustawi dane (tekst) z prawidłowego obiektu modelu danych tablicy.
  5. Teraz obrazy mogą być również w formie adresu URL, więc ten krok może być nieco dziwaczny z powodu ponownego wykorzystania komórek w widoku tabeli. Istotą faktu jest ponowne załadowanie obrazu z pamięci podręcznej urządzenia / adresu URL za pomocą kolejki asynchronicznej, a następnie ustawienie prawidłowego cell.image (niezależnie od właściwości obrazu komórki).

Aby uniknąć problemów, zapoznaj się z tym samouczkiem dotyczącym leniwego ładowania obrazów w widoku tabeli.

Nirav Bhatt
źródło