2012-04-19 18 views
8

Napisałem aplikację do testowania wydajności obrazu w systemie iOS. Wypróbowałem 3 różne widoki, wszystkie wyświetlające ten sam duży plik PNG. Pierwszy to widok, który rysuje za pomocą CGContextDrawImage(). Drugi ustawia self.layer.content. Trzeci to zwykły UIImageView.UIImageView wyświetla DUŻO szybciej niż CG lub CALayer. Ktoś wie dlaczego?

Użyte zdjęcie jest tworzone za pomocą - [UIImage initWithContentsOfData:] i buforowane w viewController. Każdy test wielokrotnie przydziela widok, dodaje go do hierarchii widoków, a następnie usuwa i zwalnia. Czasy są pobierane od początku loadView do viewDidAppear i podawane jako fps (efektywnie, wyświetlaj remisy na sekundę).

Oto wyniki od 1 iPad z systemem 5.1, stosując 912 x 634 nieskalowanego obrazu:

CGContext: 11 fps 
CALayer:  10 fps 
UIImageView: 430 fps (!) 

Am I halucynacje? Wydaje się prawie niemożliwe, że UIImageView może pobierać tak szybko, ale faktycznie mogę oglądać migotanie obrazów. Próbowałem zamieniać między dwoma podobnymi widokami, aby pokonać możliwe buforowanie, ale szybkość klatek była jeszcze wyższa.

Zawsze zakładałem, że UIImageView było tylko opakowaniem dla - [CALayer setContent]. Jednak profilowanie UIImageView pokazuje prawie brak czasu spędzonego na dowolnej metodzie rysowania, którą mogę zidentyfikować.

Chciałbym zrozumieć, co się dzieje. Każda pomoc będzie najbardziej ceniona.

+1

Edytuj swoje pytanie, dołączając kod, którego czas dotyczył w każdym przypadku, lub link do niego. –

+0

Kod jest częścią większej aplikacji używanej do testowania naszego zastrzeżonego kodu gry. Zajmie to kilka godzin, aby wyciągnąć odpowiednie fragmenty. W międzyczasie z przyjemnością odpowiem na wszelkie szczegóły, których brakuje w powyższym opisie. –

+0

"Czasy są pobierane od początku loadView do viewDidAppear" - to wydaje się trochę fałszywe, ponieważ 'viewDidAppear' może zostać wywołany, zanim widok faktycznie pojawi się na ekranie.Jeśli nie zmuszasz ekranu do aktualizacji, nie jesteś w stanie wyczuć niczego użytecznego; możesz utworzyć i zniszczyć kilka UIImageViews, ale tylko jeden zostanie narysowany. Zastanawiam się, czy UIImageView ustawia zawartość swojej warstwy na żądanie w "-layoutSubviews" - to na pewno ja bym to zrobił, aby upewnić się, że dotknąłem warstwy tylko raz na aktualizację ekranu. –

Odpowiedz

1

Oto mój pomysł.

Po zmodyfikowaniu hierarchii UIView, dodając, usuwając lub modyfikując niektóre widoki, nie jest jeszcze wykonywany rzeczywisty rysunek. Zamiast tego widok jest oznaczony "setNeedsDisplay" i jest przerysowywany następnym razem, gdy pętla runowa będzie wolna do narysowania.

W rzeczywistości, jeśli kod testowania wygląda mniej więcej tak (mogę się tylko domyślać):

for (int i=0; i<10000; i++) { 
    UIImageView* imageView = [[UIImageView alloc] initWithFrame:frame]; 
    [mainView addSubview: imageView]; 
    [imageView setImage: image]; 
    [mainView removeSubview: imageView]; 
} 

niż runloop jest zablokowany dopóki pętli jest wykonywana. Hierarchia widoków jest rysowana tylko raz, zmierzona wydajność polega na alokowaniu i inicjowaniu obiektów.

Z drugiej strony, CGContextDrawImage() jest wolny od razu, myślę.

+1

Tak, zdecydowanie tego nie robię. Jest to jednak rozsądne przypuszczenie. Moja sekwencja testowa powraca do pętli uruchamiania po każdym kroku. Jesteśmy na środku wielkiego wydania w Funzio, ale jutro spróbuję dostać kopię projektu na github. Dzięki za pomoc. –

1

Wysoki FpS z UIImageView jest taki, że tak naprawdę nie odrysowuje, ale zaznacza tylko zawartość do przerysowania czasami w przyszłości, gdy UIKit ma ochotę to zrobić.

Na marginesie: Co jest dziwne, ale CGContextmethod jest szybszy niż CALayermethod. Próbowałem również tych metod w moim projekcie, a praca z CALayerem jest najszybszą metodą (z wyjątkiem oczywiście korzystania z OpenGL ES).

Powiązane problemy