Ios 为什么这段代码解压UIImage要比原始方法好得多?

Ios 为什么这段代码解压UIImage要比原始方法好得多?,ios,objective-c,performance,uiimage,Ios,Objective C,Performance,Uiimage,在我的应用程序中,我需要加载大型JPEG图像并以滚动视图显示它们。为了保持UI的响应性,我决定在后台加载图像,然后在主线程上显示它们。为了在背景中完全加载它们,我强制对每个图像进行解压缩。我用这段代码解压了一个图像(注意我的应用程序只有iOS 7,所以我知道在后台线程上使用这些方法是可以的): 然而,我仍然有很长的加载时间、UI口吃和很大的内存压力。我刚刚发现: 这段代码好几个数量级。图像几乎是立即加载的,没有用户界面结巴,内存使用率也大大降低了 所以我的问题有两个: 为什么第二种方法比第一种好

在我的应用程序中,我需要加载大型JPEG图像并以滚动视图显示它们。为了保持UI的响应性,我决定在后台加载图像,然后在主线程上显示它们。为了在背景中完全加载它们,我强制对每个图像进行解压缩。我用这段代码解压了一个图像(注意我的应用程序只有iOS 7,所以我知道在后台线程上使用这些方法是可以的):

然而,我仍然有很长的加载时间、UI口吃和很大的内存压力。我刚刚发现:

这段代码好几个数量级。图像几乎是立即加载的,没有用户界面结巴,内存使用率也大大降低了

所以我的问题有两个:

  • 为什么第二种方法比第一种好得多
  • 如果第二种方法由于设备的独特参数而更好,那么有没有办法确保它在当前和将来的所有iOS设备上都同样有效?我不想假设一个本地位图格式在我身上发生了变化,从而再次引发这个问题

  • 我想你是在视网膜设备上运行的。在
    UIGraphicsBeginImageContextWithOptions
    中,您询问了默认比例,即主屏幕的比例,即2。这意味着它正在生成一个4倍大的位图。在第二个函数中,以1x比例绘制


    尝试将1的刻度传递到
    UIGraphicsBeginImageContextWithOptions
    ,看看您的性能是否相似。

    。是的,我在视网膜设备上运行,是的,设置scale=1可以提供类似的性能和内存使用。现在我将使用第一种方法,因为我认为无论设备的特性如何,它都会做正确的事情。为了实现这两个方面的最佳效果(速度和美观,以牺牲更多代码为代价),您可能需要显示一个快速1x渲染(甚至是0.5x渲染)如果图像仍在屏幕上,请稍后返回并填充视网膜渲染。例如,请参见(这是iOS 6编程《突破极限》第13章中的内容;今年晚些时候发布时,它将成为iOS 7 PTL中的第9章。)将UIGraphicsBeginImageContextWithOptions更改为scale=1会使图像渲染在放大时质量非常差。使用CGImage的代码以高质量渲染,就像没有使用强制解压缩一样。此外,UIGraphicsBeginImageContextWithOptions指定为不透明,不适用于透明度
    + (UIImage *)decompressedImageFromImage:(UIImage *)image {
        UIGraphicsBeginImageContextWithOptions(image.size, YES, 0);
        [image drawAtPoint:CGPointZero];
        UIImage *decompressedImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return decompressedImage;
    }
    
    + (UIImage *)decodedImageWithImage:(UIImage *)image {
        CGImageRef imageRef = image.CGImage;
        // System only supports RGB, set explicitly and prevent context error
        // if the downloaded image is not the supported format
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
        CGContextRef context = CGBitmapContextCreate(NULL,
                                                     CGImageGetWidth(imageRef),
                                                     CGImageGetHeight(imageRef),
                                                     8,
                                                     // width * 4 will be enough because are in ARGB format, don't read from the image
                                                     CGImageGetWidth(imageRef) * 4,
                                                     colorSpace,
                                                     // kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little
                                                     // makes system don't need to do extra conversion when displayed.
                                                     kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
        CGColorSpaceRelease(colorSpace);
    
        if ( ! context) {
            return nil;
        }
        CGRect rect = (CGRect){CGPointZero, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)};
        CGContextDrawImage(context, rect, imageRef);
        CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context);
        CGContextRelease(context);
        UIImage *decompressedImage = [[UIImage alloc] initWithCGImage:decompressedImageRef];
        CGImageRelease(decompressedImageRef);
        return decompressedImage;
    }