2012-05-01 5 views
9

Mam niestandardowy obiekt UITableViewCell, który składa się z UIImageView i UILabel. Komórka ma wymiary 320 x 104 piksele, a obrazView zajmuje cały obszar z etykietą z przodu. Jest tylko 8 komórek.Niestandardowy UITableViewCell z dużym UIImageView powodującym opóźnienie przewijania

w ViewDidLoad Tworzę wszystkie potrzebne obrazy z góry i zapisuję je w słowniku o prawidłowych wymiarach.

Podczas przewijania UITableView występuje zauważalne opóźnienie za każdym razem, gdy napotyka się nową komórkę. To nie ma dla mnie sensu, ponieważ obraz, którego używa, jest już utworzony i przechowywany w pamięci podręcznej. Wszystko, o co proszę komórkę, to jej UIImageView do renderowania obrazu.

Używam komórki niestandardowego z jej widoku w xib i konfigurowanie mój UITableView go używać z:

[self.tableView registerNib: [UINib nibWithNibName: @ "ActsCell" wiązki: nil] forCellReuseIdentifier: myIdentifier];

tworzenie i konfiguracja komórek:

- (UITableViewCell *)tableView:(UITableView *)tableView 
     cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSString* reuseIdentifier = @"ActsCell"; 
    ActsCell* cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; 
    // Configure the cell... 
    [self configureCell:cell atIndexPath:indexPath]; 
    return cell; 
} 

- (void)configureCell:(ActsCell *)cell atIndexPath:(NSIndexPath *)indexPath 
{ 
    Act* act = [self.acts objectAtIndex:indexPath.row]; 
    cell.selectionStyle = UITableViewCellSelectionStyleNone; 
    cell.title.text = act.name; 
    cell.imageView.image = [self.imageCache objectForKey:act.uid]; 
} 

co może być przyczyną opóźnienia? Wydaje się, że nie ma żadnej korzyści, jeśli chodzi o próbę zrobienia czegoś Asynchronicznego, ponieważ wykonywana jest cała czasochłonna praca.

+0

Mogę wymyślić dwie rzeczy. Jedną z nich jest to, że puszczanie pakietów kończy się niepowodzeniem, ponieważ nie ustawiasz poprawnie 'reusableIdentifier'. Drugi to rozmiar obrazów. Mimo że obrazy są załadowane, CG musi przetworzyć dane obrazu przed wyświetleniem, co może wymagać kosztownych operacji, takich jak skalowanie, kompozycja itp. – Lvsti

+0

@ Lvsti Czy możesz wyjaśnić, w jaki sposób właściwie nie ustawiam reuseIdentifier? – Undistraction

+0

masz rację, prawdopodobnie tak nie jest, w przeciwnym razie nie otrzymasz żadnych komórek z powrotem po usunięciu z listy ... – Lvsti

Odpowiedz

28

Czy ładujesz obrazy z plików lokalnych przez przypadek?

Korzystając z Instrumentów Stwierdziłem, że istnieje pewien leniwy mechanizm ładujący w UIImage - rzeczywiste dane obrazu zostały zdekompresowane z PNG tylko na etapie renderowania go na głównym wątku, który powodował opóźnienie podczas przewijania.

Tak, po załadunku UIImage z -initWithContentsOfFile: metodzie Dodałem kod do renderowania zawartości tego obrazu do niewidocznej kontekście, że kontekst zapisany jako nowy UIImage i używali go do UIImageView w UITableViewCell, to sprawiło, że do przewijania bądź znów gładka i miła dla oka.

W przypadku odniesienia nie jest prosty kod używam wymusić odczyt zawartości obrazu w osobnym wątku (stosując ARC):

UIImage *productImage = [[UIImage alloc] initWithContentsOfFile:path]; 

CGSize imageSize = productImage.size; 
UIGraphicsBeginImageContext(imageSize); 
[productImage drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)]; 
productImage = UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 

I myślę, że powierzchnia UIImage stworzony w taki sposób, będzie w obsługiwanym formacie dostosowanym do renderowania, co spowoduje również zwolnienie pracy wymaganej do renderowania w głównym wątku.

EDYCJA: Dokumenty dla mówią, że powinny być używane tylko z głównego wątku, ale wyszukiwanie w sieci lub SO pokazuje, że począwszy od iOS 4, metody UIGraphics.. stały się bezpieczne dla wątków.

+5

To było dla mnie absolutnie nieocenione. Cierpiałem na nieustanne przewijanie na UICollectionView z UIImageViews w każdej komórce, aby wyświetlić zdjęcie. Próbowałem * wiele * różnych rozwiązań, ale jedyny sposób, w jaki udało mi się zbliżyć do 60FPS, był wyjątkowo hackowy. Większość rozwiązań próbowałem wstępnego ładowania NSCache UIImages przy użyciu imageWithContentsOfFile, ale cokolwiek robiłem tam zawsze był mały skok, jak nowe komórki pojawiły się na ekranie, aż zaimplementowałem twój kod powyżej. Jak mówisz, musi istnieć jakiś leniwy mechanizm ładujący wbudowany w imageWithContentsOfFile, który nie jest wspomniany w dokumentach. – alistairholt

+0

Ta praca dla mnie, znacznie bardziej płynna po przechowywaniu UIImage zamiast pobranych danych, a następnie konwertowania do UIImage za każdym razem, gdy zostanie użyty. Dziękuję bardzo. – Envil

+0

Szukałem tak długo dla powolnej/niepewnej przyczyny. Ty jesteś bohaterem – user1838169