2010-10-11 13 views
10

Mam wątek tła, który ładuje obrazy i wyświetla je w wątku głównym. I zauważyłem, że wątek tła ma prawie nic wspólnego, ponieważ rzeczywista dekodowania obrazu wydaje się być zrobione w głównym wątku:Odkodować obrazy w wątku tła?

alt text

Do tej pory próbowałem dzwoniąc [UIImage imageNamed:], [UIImage imageWithData:] i CGImageCreateWithJPEGDataProvider w tle wątek bez różnicy. Czy istnieje sposób na wymuszenie dekodowania na wątku tła?

Tutaj jest już a similar question, ale to nie pomaga. Jak pisałem tam, próbowałem następującą sztuczkę:

@implementation UIImage (Loading) 

- (void) forceLoad 
{ 
    const CGImageRef cgImage = [self CGImage]; 

    const int width = CGImageGetWidth(cgImage); 
    const int height = CGImageGetHeight(cgImage); 

    const CGColorSpaceRef colorspace = CGImageGetColorSpace(cgImage); 
    const CGContextRef context = CGBitmapContextCreate(
     NULL, /* Where to store the data. NULL = don’t care */ 
     width, height, /* width & height */ 
     8, width * 4, /* bits per component, bytes per row */ 
     colorspace, kCGImageAlphaNoneSkipFirst); 

    NSParameterAssert(context); 
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage); 
    CGContextRelease(context); 
} 

@end 

To działa (zmusza do dekodowania obrazu), ale także wyzwala pozornie drogie połączenia do ImageIO_BGR_A_TO_RGB_A_8Bit.

Odpowiedz

7

Oficjalnie UIKit nie jest bezpieczny dla wątków (choć wydaje mi się, że jest nieco bezpieczniejszy w iOS 4), więc nie powinieneś wywoływać żadnej z metod UIImage w wątku tła. W praktyce wydaje mi się, że nie masz problemów, jeśli nie robisz niczego, co powoduje, że obiekt UIKit chce przerysować, ale jest to reguła, której nigdy nie należy polegać na kodzie wysyłki - wspominam o tym tylko po to, aby wyjaśnić, dlaczego prawdopodobnie nie miałeś problemu.

Jak zauważyliście, CGImageRefs (w tym również zawinięte w UIImage) nadal odnoszą się do obrazów źródłowych w ich zakodowanej formie, chyba że ktoś potrzebuje ich odkodowania. "Podstęp", który cytujesz, skutecznie wyzwala dekodowanie; lepszym rozwiązaniem jest całkowite uniknięcie UIImage, dopóki bezpiecznie nie wrócisz do głównego wątku, zacznij od CGImageCreateWithJPEGDataProvider, utwórz oddzielny kontekst jak powyżej, CGContextDrawImage z JPEGDataProvider do nowego kontekstu, a następnie podaj nowy kontekst jako obraz, zwalniając dostawcę danych JPEG.

W odniesieniu do ImageIO_BGR_A_TO_RGB_A_8Bit, może warto dając CGColorSpaceCreateDeviceRGB() odchodzenie zamiast CGImageGetColorSpace (cgImage), aby uzyskać kontekst z przestrzeni kolorów, które nie zależą od pliku obrazu źródłowego pod spodem.

10

Wystąpiłem podobne problemy z obrazami wysokiej rozdzielczości na nowym iPodzie siatkówki. Obrazy większe niż rozmiar ekranu (z grubsza) spowodowałyby poważne problemy z reagowaniem interfejsu użytkownika. Były to pliki JPG, więc sprawdzenie, czy są one w tle, wydaje się słuszne. Nadal pracuję nad zaostrzeniem tego wszystkiego, ale rozwiązanie Tommy'ego sprawdziło się doskonale. Po prostu chciałem dodać trochę kodu, aby pomóc kolejnej osobie, gdy próbują ustalić, dlaczego ich interfejs użytkownika jąka się z dużymi obrazami. Oto, co robiłem (ten kod działa w NSOperation w kolejce w tle). Przykład to mieszanka mojego kodu i powyższego kodu:

CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((CFDataRef)self.data); 
    CGImageRef newImage = CGImageCreateWithJPEGDataProvider(dataProvider, 
            NULL, NO, 
            kCGRenderingIntentDefault); 


    ////////// 
    // force DECODE 

    const int width = CGImageGetWidth(newImage); 
    const int height = CGImageGetHeight(newImage); 

    const CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); 
    const CGContextRef context = CGBitmapContextCreate(
                NULL, /* Where to store the data. NULL = don’t care */ 
                width, height, /* width & height */ 
                8, width * 4, /* bits per component, bytes per row */ 
                colorspace, kCGImageAlphaNoneSkipFirst); 

    NSParameterAssert(context); 
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), newImage); 
    CGImageRef drawnImage = CGBitmapContextCreateImage(context); 
    CGContextRelease(context); 
    CGColorSpaceRelease(colorspace); 

    ////////// 

    self.downloadedImage = [UIImage imageWithCGImage:drawnImage]; 

    CGDataProviderRelease(dataProvider); 
    CGImageRelease(newImage); 
    CGImageRelease(drawnImage); 

Nadal to optymalizuję. Ale wydaje się, że do tej pory całkiem dobrze.

+0

dziękuję, działa świetnie. – Morrowless

Powiązane problemy