2013-10-30 31 views
8

在我的应用程序中,我需要加载较大的JPEG图像并将它们显示在滚动视图中。为了保持UI的响应,我决定在后台加载图像,然后将它们显示在主线程中。为了在后台完全加载它们,我强制每个图像进行解压缩。我使用此代码来解压缩的图像为(请注意,我的应用程序是仅适用于iOS 7,所以我的理解是用在后台线程这些方法是OK):为什么这段代码比简单的方法更好地解压UIImage?

+ (UIImage *)decompressedImageFromImage:(UIImage *)image { 
    UIGraphicsBeginImageContextWithOptions(image.size, YES, 0); 
    [image drawAtPoint:CGPointZero]; 
    UIImage *decompressedImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return decompressedImage; 
} 

然而,我仍然有很长的负载时间,UI口吃和很多内存压力。我刚刚发现another solution

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

该代码的大小更好的订单。图像几乎立即加载,没有UI口吃,并且内存使用已经下降。

所以我的问题是双重的:

  1. 为什么第二种方法比第好多了?
  2. 如果第二种方法由于设备的独特参数而更好,是否有办法确保它可以同样适用于所有iOS设备,现在和将来?我不想假设一个本地位图格式在我身上发生变化,重新引入此问题。

回答

6

我假设你在Retina设备上运行这个。在UIGraphicsBeginImageContextWithOptions中,您要求使用默认比例尺,即主屏幕的比例,即2。这意味着它生成的比特图大小为4x。在第二个函数中,您以1x比例绘制。

尝试将1的比例传递给UIGraphicsBeginImageContextWithOptions,看看你的表现是否相似。

+0

辉煌。是的,我在视网膜设备上运行,是的,设置scale = 1给我类似的性能和内存使用。现在我将采用第一种方法,因为无论设备的特性如何,我都希望它能做正确的事情。 –

+0

为了获得两全其美(速度和美感,代价更高的代码),您可能需要显示一个快速的1x渲染(甚至是0.5x渲染),然后返回并在稍后填写视网膜渲染。图像仍然在屏幕上。有关示例,请参阅https://github.com/iosptl/ios6ptl/tree/master/ch13/JuliaOp(这是来自iOS 6编程推动限制的第13章;它将成为iOS 7 PTL中的第9章) ) –

+0

将UIGraphicsBeginImageContextWithOptions更改为scale = 1时,缩放时会使图像渲染质量很差。使用CGImage的代码以高质量渲染,就像不使用强制解压缩一样。 此外,UIGraphicsBeginImageContextWithOptions指定为不透明,不适用于透明度 –

相关问题