2012-02-10 13 views
6

chcę wczytywać obrazy Sot, że kiedy dodać swój UIImageView do mojego currentView, PNG są już w pamięci, załadowany, napompowane itpWymuszenie obciążenia obrazów na iOS przekręceniem

Jak widać z tego czas profilowania, obrazy są ładowane, gdy są wyświetlane: enter image description here

W tym samym czasie już wstępnie ładuję te obrazy. Po prostu, kiedy załadować ten pogląd, ja dokładnie utworzyć wszystkie obrazy i widoki graficzne dla tych animacji przy użyciu tego kodu:

- (UIImageView*)createAnimationForReel:(NSString*)reel ofType:(NSString*)type usingFrames:(NSInteger)frames{ 
    UIImageView *imageView = [[UIImageView alloc] init]; 
    NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:frames]; 

    for (int i=0;i<frames;i++){ 
     NSString *image; 
     if(i<10){ 
      image = [NSString stringWithFormat:@"%@_0%i", reel, i]; 
     } else { 
      image = [NSString stringWithFormat:@"%@_%i", reel, i]; 
     } 
     NSString *path = [[NSBundle mainBundle] pathForResource:image ofType:@"png" inDirectory:type]; 
     UIImage *anImage = [[UIImage alloc] initWithContentsOfFile:path]; 
     [imageArray addObject:anImage]; 
    } 
    imageView.animationImages = [NSArray arrayWithArray:imageArray]; 
    imageView.animationDuration = 2.0; 
    return imageView; 
} 

I kiedy czytam dokumentację mówi: „Ta metoda ładuje dane obrazu do pamięci i oznacza go Jeśli dane zostały wyczyszczone i muszą zostać ponownie załadowane, obiekt obrazu wczytuje te dane ponownie z określonej ścieżki. " mówienie o initWithContentOfFile. Dlatego mój obraz "powinien" zostać załadowany.

Ale nie.

Z pewnością czegoś brakuje w moim odbiciu. Ale co?

Odpowiedz

0

Sposób byłoby użycie ImageIO ramy (iOS 4.0+) i zrobić coś takiego:

NSDictionary* dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:(id)kCGImageSourceShouldCache]; 

CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)url, NULL); 
CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, 0, (CFDictionaryRef)dict); 

UIImage* retImage = [UIImage imageWithCGImage:cgImage]; 
CGImageRelease(cgImage); 
CFRelease(source); 
+0

Wygląda wspaniale i rzeczywiście wczytuje obrazy, z wyjątkiem sytuacji, gdy nie są one buforowane i nadal są ponownie ładowane za każdym razem, gdy są wyświetlane. Taki wstyd! Zaczynam myśleć, że ma to więcej wspólnego ze sposobem działania UIImageView, a nie z UIImage. –

12

Aby wymusić pełną obciążenia wstępnego w UIImage, trzeba rzeczywiście wyciągnąć go, czy tak wydaje się. Na przykład:

- (void)preload:(UIImage *)image 
{ 
    CGImageRef ref = image.CGImage; 
    size_t width = CGImageGetWidth(ref); 
    size_t height = CGImageGetHeight(ref); 
    CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, width * 4, space, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedFirst); 
    CGColorSpaceRelease(space); 
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), ref); 
    CGContextRelease(context); 
} 

Nie jest ładna, ale powoduje, że rysunek obrazka o 4x szybciej. Testowałem to z 1 MB 640 × 1136 PNG na iPhonie 4S:

  • Rysowanie bez obciążenia wstępnego trwa około 80 ms.
  • Wstępne ładowanie nagłówka obrazu trwa około 10 ms, ale później nie przyspiesza rysowania.
  • Wstępne ładowanie danych przez dostawcę danych trwa około 100 ms, ale prawie nie przyspiesza późniejszego rysowania.
  • Wstępne ładowanie za pomocą rysunku, pokazanego w powyższym kodzie, trwa 100 ms, ale następne losowanie to tylko 20 ms.

Sprawdź kod testowy pod numerem https://gist.github.com/3923434.

+0

Użycie tego w wątku tła znacznie poprawiło wydajność mojej aplikacji, ponieważ nie blokowałoby głównego wątku wczytywania danych. Dzięki :) – bendahmon

+0

To niesamowite ulepszenie rysowania obrazów - dzięki! Dostaję ostrzeżenie o niejawnej konwersji w odniesieniu do "kCGImageAlphaPremultipliedFirst" –

+0

Dziękuję Jayowi za wskazanie ostrzeżenia, powinno to teraz zostać naprawione. – leo

0

Odpowiedź Leo prawie nie dała mi żadnego przyspieszenia ładowania prędkości. Efekt był zauważalny tylko wtedy, gdy raz po raz ładuję jeden obraz po raz drugi. Jeśli wywołasz preload przez kliknięcie przycisku, na przykład, pierwsze obciążenie wstępne daje około 40 ms doładowania, jeśli początkowe obciążenie wynosi 200 ms. To niewiele.

Aby rozwiązać mój problem, właśnie utworzyłem ukryte obrazy i dodałem je do widoku hierarchii, gdzie potrzebowałem wstępnego załadowania. Następny ładunek tych obrazów trwał blisko 10 ms.

Powiązane problemy