Ustawienie właściwości obrazu UIImageView powoduje duże opóźnienie

Pozwól, że opowiem ci o moim problemie i o tym, jak próbowałem go rozwiązać. Mam UIScrollView, który ładuje podview jak jeden przewija od lewej do prawej. Każdy subview ma 10-20 obrazów około 400x200 każdy. Kiedy przewijam z widoku na widok, doświadczam sporego opóźnienia.

Po zbadaniu, odkryłem, że po rozładowaniu wszystkich widoków i ponownym wypróbowaniu, opóźnienie zniknęło. Pomyślałem, że synchroniczne buforowanie obrazów było przyczyną opóźnienia. Więc stworzyłem podklasa UIImageView, która ładowała obrazy asynchronicznie. Kod ładowania wygląda następująco (self.dispatchQueue zwraca kolejkę wysyłania seryjnego).

- (void)loadImageNamed:(NSString *)name {
    dispatch_async(self.dispatchQueue, ^{
        UIImage *image = [UIImage imageNamed:name];

        dispatch_sync(dispatch_get_main_queue(), ^{
            self.image = image;
        });
    });
}

Jednak, po zmianie Wszystkich moich UIImageViews na tę podklasę, nadal doświadczyłem lag (nie jestem pewien, czy został zmniejszony, czy nie). Zmniejszyłem przyczynę problemu do self.image = image;. Dlaczego powoduje to tak duże opóźnienie (ale tylko przy pierwszym obciążeniu)?

Proszę, pomóż mi. =(
Author: fumoboy007, 2012-05-29

2 answers

EDIT 2: Oto wersja Swift, która zawiera kilka ulepszeń. (Nieprzetestowane.) https://gist.github.com/fumoboy007/d869e66ad0466a9c246d


EDIT: właściwie, uważam, że wszystko, co jest konieczne, to następujące rzeczy. (Nieprzetestowane.)

- (void)loadImageNamed:(NSString *)name {
    dispatch_async(self.dispatchQueue, ^{
        // Determine path to image depending on scale of device's screen,
        // fallback to 1x if 2x is not available
        NSString *pathTo1xImage = [[NSBundle mainBundle] pathForResource:name ofType:@"png"];
        NSString *pathTo2xImage = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"png"];

        NSString *pathToImage = ([UIScreen mainScreen].scale == 1 || !pathTo2xImage) ? pathTo1xImage : pathTo2xImage;


        UIImage *image = [[UIImage alloc] initWithContentsOfFile:pathToImage];

        // Decompress image
        if (image) {
            UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);

            [image drawAtPoint:CGPointZero];

            image = UIGraphicsGetImageFromCurrentImageContext();

            UIGraphicsEndImageContext();
        }


        // Configure the UI with pre-decompressed UIImage
        dispatch_async(dispatch_get_main_queue(), ^{
            self.image = image;
        });
    });
}

Oryginalna odpowiedź: okazuje się, że to nie było self.image = image; bezpośrednio. Metody ładowania obrazów UIImage nie dekompresują i nie przetwarzają danych obrazu od razu; robią to, gdy Widok odświeża swój wyświetlacz. Więc rozwiązaniem było, aby przejść obniż poziom do podstawowej grafiki i dekompresuj i przetwarzaj dane obrazu samodzielnie. Nowy kod wygląda następująco.

- (void)loadImageNamed:(NSString *)name {
    dispatch_async(self.dispatchQueue, ^{
        // Determine path to image depending on scale of device's screen,
        // fallback to 1x if 2x is not available
        NSString *pathTo1xImage = [[NSBundle mainBundle] pathForResource:name ofType:@"png"];
        NSString *pathTo2xImage = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"png"];

        NSString *pathToImage = ([UIScreen mainScreen].scale == 1 || !pathTo2xImage) ? pathTo1xImage : pathTo2xImage;


        UIImage *uiImage = nil;

        if (pathToImage) {
            // Load the image
            CGDataProviderRef imageDataProvider = CGDataProviderCreateWithFilename([pathToImage fileSystemRepresentation]);
            CGImageRef image = CGImageCreateWithPNGDataProvider(imageDataProvider, NULL, NO, kCGRenderingIntentDefault);


            // Create a bitmap context from the image's specifications
            // (Note: We need to specify kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little
            // because PNGs are optimized by Xcode this way.)
            CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
            CGContextRef bitmapContext = CGBitmapContextCreate(NULL, CGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBitsPerComponent(image), CGImageGetWidth(image) * 4, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);


            // Draw the image into the bitmap context
            CGContextDrawImage(bitmapContext, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);

            //  Extract the decompressed image
            CGImageRef decompressedImage = CGBitmapContextCreateImage(bitmapContext);


            // Create a UIImage
            uiImage = [[UIImage alloc] initWithCGImage:decompressedImage];


            // Release everything
            CGImageRelease(decompressedImage);
            CGContextRelease(bitmapContext);
            CGColorSpaceRelease(colorSpace);
            CGImageRelease(image);
            CGDataProviderRelease(imageDataProvider);
        }


        // Configure the UI with pre-decompressed UIImage
        dispatch_async(dispatch_get_main_queue(), ^{
            self.image = uiImage;
        });
    });
}
 53
Author: fumoboy007,
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
2016-01-20 21:18:09

Myślę, że problemem mogą być same obrazy. Na przykład-dostałem w jednym z moich projektów 10 obrazów 640x600 warstwowych z przezroczystością alfa na siebie. Kiedy próbuję wypchnąć lub pop viewcontroller z tego viewcontroller.. bardzo długo.

Kiedy zostawiam tylko kilka zdjęć lub używam dość mniejszych zdjęć-bez opóźnień.

P. S. testowany na sdk 4.2 iOS5 iphone 4.

 1
Author: Guntis Treulands,
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
2012-05-28 20:51:27