Jak mogę przyspieszyć UITableView?

Mam UITableView z około 400 komórkami w 200 sekcjach i jest trochę powolny w reagowaniu na interakcję z użytkownikiem (przewijanie, wybieranie komórek.) Upewniłem się, że metody pobierania komórek i widoków nagłówków robią minimalne minimum, ponieważ działa, i nie sądzę, że robię coś niezwykłego, aby zwolnić. Komórki i nagłówki mają tylko obraz tła i tekst. Czy ktoś jeszcze miał taki problem i czy znasz jakiś sposób, aby go uruchomić trochę szybciej?

Edit: oferuję nagrodę, ponieważ chciałbym uzyskać kilka przydatnych opinii na ten temat. Nie sądzę, że odpowiedź leży w problemie w moim kodzie. Zamiast tego Szukam strategii, aby ponownie zaprojektować UITableView, aby działał szybciej. Jestem całkowicie otwarty na dodawanie nowego kodu i czekam na to, co macie do powiedzenia.

Ospałość jest obserwowana zarówno na symulatorze, jak i moim urządzeniu, iPhone 4. Oto moje implementacje viewForHeaderInSection i cellForRowAtIndexPath, które są jedynymi metodami UITableViewDelegate zaimplementowanymi nietrywialnie. Używam ponownie komórek i widoków nagłówków.

- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger) section
{
    HaikuHeaderView* view= [m_sectionViews objectAtIndex:section];
    NSMutableArray* array= [m_haikuSearch objectAtIndex:section];
    Haiku* haiku= [array objectAtIndex:0];

    [view.poetLabel setText:[haiku nameForDisplay]];

    return view;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];

        cell.backgroundView= [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell gradient2.png"]];

        // (Set up a bunch of label attributes in the cell...)
    }

    NSMutableArray* array= [m_haikuSearch objectAtIndex:indexPath.section];
    Haiku* haiku = [array objectAtIndex:indexPath.row];
    cell.textLabel.text = [haiku.m_lines objectAtIndex:0];

    return cell;
}
Author: Irfan, 2011-05-30

9 answers

Nawet jeśli Twoja komórka jest tak prosta (obraz tła i etykieta), należy wziąć pod uwagę kilka rzeczy

Image caching Jest to oczywiste - jeśli używasz tego samego obrazu wszędzie, załaduj go raz do UIImage i użyj go ponownie. Nawet jeśli system będzie buforować go samodzielnie, bezpośrednio przy użyciu już załadowanego nigdy nie powinno zaszkodzić.

Szybkie obliczanie Kolejna dość oczywista rzecz - spraw, aby obliczanie wysokości i treści było tak szybkie, jak to możliwe. Nie. wykonuj synchroniczne pobieranie (połączenia sieciowe, odczyty dysków itp.).

Kanał alfa na obrazku To, co jest drogie podczas rysowania, to przezroczystość. Ponieważ tło komórki nie ma nic za sobą, upewnij się, że zapisujesz obraz bez kanału alfa. To oszczędza dużo przetwarzania.

Przezroczysta Etykieta To samo dotyczy etykiety na górze widoku tła, niestety jej nieprzezroczystość może zrujnować wygląd komórki - ale zależy to od obrazu.

Custom cell Ogólnie rzecz biorąc, podklasowanie UITableViewCell i implementacja drawRect: jest szybsze niż budowanie hierarchii subview. Obraz może być zmienną klasy używaną przez wszystkie instancje. W drawRect: narysujesz obrazek i tekst na nim.

Check compositing Symulator ma narzędzie do zaznaczania części, które są renderowane-drogie ze względu na przezroczystość(zielony jest w porządku, czerwony jest mieszanie Alfa). Można go znaleźć w menu debugowania: "Color Blended Warstwy "

 47
Author: Eiko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-03 10:11:03

Najlepszą rzeczą, jaką możesz zrobić, jeśli chcesz przyspieszyć kod, jest jego profilowanie. Są dwa powody:

  1. Możesz przeczytać o niektórych rzeczach, które poprawią wydajność tabeli w ogóle, jak używanie komórek o stałej wysokości i ponowne użycie komórek, i prawdopodobnie pomoże to zaimplementować te rzeczy (wygląda na to, że już to zrobiłeś). Ale jeśli chodzi o przyspieszenie Twój kod, naprawdę musisz wiedzieć, gdzie aplikacja spędza większość swojego czasu. Może być że istnieje kilka metod, które zajmują bardzo dużo czasu, lub metoda, która jest stosunkowo szybka, ale jest wywoływana znacznie częściej niż można się spodziewać.

  2. Nie można dowiedzieć się, czy zmiany, które wprowadzasz, aby przyspieszyć działanie, naprawdę mają znaczenie, chyba że masz pewne liczby do zmierzenia. Jeśli możesz pokazać, że twój kod spędzał 80% swojego czasu w jednej rutynie i ograniczysz go do 35%, wiesz, że robisz postępy.

Więc wyłam się Przyrządy i zacznij mierzyć. Jeśli możesz, dobrze jest zmierzyć każdą z różnych czynności, które chcesz przyspieszyć... wykonaj jedną sesję profilowania podczas przewijania, jedną podczas wybierania jak największej liczby różnych komórek w określonym czasie itp. Nie zapomnij zapisać wyników, aby można było porównać później.

 9
Author: Caleb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-21 04:51:58

Zwróć uwagę na te punkty..

    Czy używasz ponownie komórek?.Czyli dobra praktyka do zrobienia..
  1. Upewnij się, że nie robisz żadnych kosztowne obliczenia w cellForRowAtIndexPath callback, lub w funkcji wywołanej z / Align = "left" / .
  2. powiedziałeś, że jest tło obraz. Kolejny powód, dla którego musisz użyj ponownie swojej komórki.

Kilka dobrych informacji na temat ponownego użycia komórek jest tutaj ..

EDIT: znalazłem tę stronę bardzo późno..

Ten więc pytanie wątek może Ci pomóc...zwłaszcza zaakceptowaną odpowiedź...

 5
Author: Krishnabhadra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:34
  1. Użyj współdzielonej instancji obrazu dla tła (alloc / init / release one for every time a new cell is created). Gdy widok tabeli jest duży, oznacza to, że komórki X tła w pamięci zajmują znacznie więcej pamięci niż powinno.

    Zamiast
    cell.backgroundView= [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell gradient2.png"]];
    wystarczy użyć :
    cell.backgroundView= [SomeHelperClass sharedBackgroundUIImageResource];

  2. Jeśli to nie pomoże, użyj CG zamiast etykiet i innych podglądów (tutaj pomoże zrzut ekranu.. wiedzieć o czym mówimy).

 3
Author: Lou Weed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-23 05:21:10

Czy delegat widoku tabeli implementuje:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

Jeśli tak, możesz rozważyć ustawienie właściwości rowHeight uitableviewcell.

 2
Author: Andrew Ebling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-30 04:29:36

Czy używasz wielu podglądów?

Jeśli tak, dobrą techniką jest, aby zamiast dodawać wiele etykiet i obrazów, narysować je za pomocą CoreGraphics.

Aby to zrobić, musisz podklasować UITableViewCell i zaimplementować metodę -(void)drawRect:(CGRect)rect.

 1
Author: EmilioPelaez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-21 04:33:46

Dwie sugestie: jedną z nich jest użycie -initWithStyle:reuseIdentifier: dla komórek widoku tabeli zamiast-initWithFrame:. Drugim jest skomentowanie ustawienia komórki.widok tła do obrazu z gradientem i sprawdź, czy to jest winowajca. Za każdym razem, gdy miałem słabą wydajność w widoku tabeli, to było z powodu obrazu.

 1
Author: Drew C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-21 04:48:18

To jest trochę off-topic tutaj (ponieważ masz tylko jeden obraz tła dla wszystkich komórek):

Moja aplikacja wyświetla różne obrazy w każdej komórce. Po dodaniu około 5 komórek do UITableView-table jest drastycznie spowalniany. Przetwarzanie wszystkich obrazów zajmuje około 1-2 sekund za każdym razem, gdy otwieram kontroler widoku.

if let image = UIImage(contentsOfFile: photoFile){
    // just set it and let system fit it
    //cell.imageView!.image = image

    // 1 - Calculate sized
    let DEFAULT_THUMBNAIL_WIDTH: CGFloat  = (cellHeight / 4) * 5;
    let DEFAULT_THUMBNAIL_HEIGHT: CGFloat = cellHeight;

    let aspectRatio: CGFloat = image.size.width / image.size.height
    var willBeHeight = DEFAULT_THUMBNAIL_HEIGHT
    var willBeWidth  = DEFAULT_THUMBNAIL_HEIGHT * aspectRatio

    if(willBeWidth > DEFAULT_THUMBNAIL_WIDTH){
        willBeWidth = DEFAULT_THUMBNAIL_WIDTH
        willBeHeight = willBeWidth / aspectRatio
    }

    let eps:CGFloat = 0.000001
    assert((willBeHeight - eps) <= DEFAULT_THUMBNAIL_HEIGHT);
    assert((willBeWidth - eps) <= DEFAULT_THUMBNAIL_WIDTH);

    // 2 - Create context
    var size:CGSize = CGSize(
        width: DEFAULT_THUMBNAIL_WIDTH,
        height: DEFAULT_THUMBNAIL_HEIGHT)
    UIGraphicsBeginImageContext(size)

    // one-to-one rect
    //var imageRect: CGRect = CGRectMake(0.0, 0.0, size.width, size.height)
    var imageRect: CGRect = CGRectMake(0.0, 0.0, willBeWidth, willBeHeight)

    // 3 - Draw image
    image.drawInRect(imageRect)
    var imageResult: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    cell.imageView!.image = imageResult

    UIGraphicsEndImageContext()
}else{
    DDLogError("Can not draw photo: \(photoFile)")
}

Więc skończyłem z generowaniem małych miniaturek dla wszystkich moich zdjęć.

 0
Author: Anthony Akentiev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-27 13:44:03

Użyj ponownie komórek. Alokacja obiektów wiąże się z kosztami wydajności, zwłaszcza jeśli alokacja musi mieć miejsce wielokrotnie w krótkim czasie-np. gdy użytkownik przewija widok tabeli. Jeśli ponownie użyjesz komórek zamiast przydzielać nowe, znacznie zwiększysz wydajność widoku tabeli. Unikaj przekazywania treści. Podczas ponownego używania komórek z niestandardowymi podwidywaniami, nie należy układać tych podwidywań za każdym razem, gdy widok tabeli żąda komórki. Po utworzeniu komórki należy raz rozplanować podglądy. Użyj nieprzezroczystych podglądów podrzędnych. Podczas dostosowywania komórek widoku tabeli, upewnij się, że podview komórki jest nieprzezroczysta, a nie przezroczysta.

 -1
Author: Prerna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-22 09:34:15