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?


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

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ą.

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


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. : +)


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.