23

让我告诉你我遇到的问题以及我如何尝试解决它。我有一个 UIScrollView 加载子视图作为一个从左到右滚动。每个子视图有 10-20 个图像,每个图像大约 400x200。当我从一个视图滚动到另一个视图时,我会遇到相当多的延迟。

调查后发现,卸载所有视图后再次尝试,卡顿消失了。我认为图像的同步缓存是滞后的原因。所以我创建了一个异步加载图像的 UIImageView 的子类。加载代码如下所示(self.dispatchQueue返回一个串行调度队列)。

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

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

但是,在将我所有的 UIImageViews 更改为这个子类之后,我仍然遇到了延迟(我不确定它是否减少了)。我将问题的原因归结为self.image = image;. 为什么这会导致如此多的延迟(但仅在第一次加载时)?

请帮我。=(

4

2 回答 2

55

编辑 3:iOS 15 现在提供UIImage.prepareForDisplay(completionHandler:).

image.prepareForDisplay { decodedImage in
    imageView.image = decodedImage
}

或者

imageView.image = await image.byPreparingForDisplay()

编辑 2:这是一个包含一些改进的 Swift 版本。(未经测试。) https://gist.github.com/fumoboy007/d869e66ad0466a9c246d


编辑:实际上,我相信所有必要的都是以下内容。(未经测试。)

- (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;
        });
    });
}

原始答案:事实证明,它不是self.image = image;直接的。UIImage 图像加载方法不会立即解压缩和处理图像数据;当视图刷新其显示时,他们会这样做。所以解决的办法是降级到Core Graphics,自己解压处理图像数据。新代码如下所示。

- (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;
        });
    });
}
于 2012-05-30T15:00:36.527 回答
0

我认为,问题可能出在图像本身。例如 - 我在我的一个项目中获得了 10 张 640x600 的图像,它们相互之间具有 alpha 透明度。当我尝试从这个视图控制器推送或弹出视图控制器时......它滞后了很多。

当我只留下几张图片或使用非常小的图片时 - 没有延迟。

PS 在 sdk 4.2 ios5 iphone 4 上测试。

于 2012-05-28T20:51:27.047 回答