设置 UIImageView 的图像属性会导致严重滞后 [英] Setting image property of UIImageView causes major lag

查看:26
本文介绍了设置 UIImageView 的图像属性会导致严重滞后的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Let me tell you about the problem I am having and how I tried to solve it. I have a UIScrollView which loads subviews as one scrolls from left to right. Each subview has 10-20 images around 400x200 each. When I scroll from view to view, I experience quite a bit of lag.

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

After investigating, I discovered that after unloading all the views and trying it again, the lag was gone. I figured that the synchronous caching of the images was the cause of the lag. So I created a subclass of UIImageView which loaded the images asynchronously. The loading code looks like the following (self.dispatchQueue returns a serial dispatch queue).

- (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;.为什么这会导致如此多的延迟(但仅在第一次加载时)?

However, after changing all of my UIImageViews to this subclass, I still experienced lag (I'm not sure if it was lessened or not). I boiled down the cause of the problem to self.image = image;. Why is this causing so much lag (but only on the first load)?

请帮帮我.=(

推荐答案

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

EDIT 3: iOS 15 now offers UIImage.prepareForDisplay(completionHandler:).

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

imageView.image = await image.byPreparingForDisplay()


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

实际上,我相信所有必要的是以下内容.(未经测试.)

Actually, I believe all that is necessary is the following. (Untested.)

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


ORIGINAL ANSWER:原来不是 self.image = image; 直接.UIImage 图像加载方法不会立即解压缩和处理图像数据;他们在视图刷新显示时执行此操作.所以解决方案是降低到 Core Graphics 的级别,并自己解压和处理图像数据.新代码如下所示.


ORIGINAL ANSWER: It turns out that it wasn't self.image = image; directly. The UIImage image loading methods don't decompress and process the image data right away; they do it when the view refreshes its display. So the solution was to go a level lower to Core Graphics and decompress and process the image data myself. The new code looks like the following.

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

这篇关于设置 UIImageView 的图像属性会导致严重滞后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆