iphone - 在一个小框架中显示一个大图像UIImageView仍然需要大量内存?

时间:2011-07-20 20:10:58

标签: iphone memory uiimageview

我有几张大小约1.5 MB的大图片。我使用UIViewContentModeScaleFit在UIImageView中显示它们。

UIImageViews的帧大小只有150 * 150。

我的问题是

我知道如果我为全屏显示大图像,内存将会大幅增加。

但如果他们在小型UIImageView中,他们还会花费内存吗?

由于

4 个答案:

答案 0 :(得分:3)

UIImageUIImageView是不同的东西。每个UIImageView都知道显示其关联的UIImage的大小。 UIImage没有关于如何展示自身或如何用于展示的概念,因此仅仅改变UIImageView的大小的行为对UIImage没有影响。因此它对总内存使用量没有影响。

您可能想要做的是使用Core Graphics获取UIImage并将其生成150x150版本作为新UIImage,然后将其推送到UIImageView

要执行比例,代码类似于以下内容(按我输入的方式编写,因此未经过彻底检查)应该完成这项工作:

#include <math.h>

- (UIImage *)scaledImageForImage:(UIImage *)srcImage toSize:(CGSize)maxSize
{
    // pick the target dimensions, as though applying
    // UIViewContentModeScaleAspectFit; seed some values first
    CGSize sizeOfImage = [srcImage size];
    CGSize targetSize; // to store the output size

    // logic here: we're going to scale so as to apply some multiplier
    // to both the width and height of the input image. That multiplier
    // is either going to make the source width fill the output width or
    // it's going to make the source height fill the output height. Of the
    // two possibilities, we want the smaller one, since the larger will
    // make the other axis too large
    if(maxSize.width / sizeOfImage.width < maxSize.height / sizeOfImage.height)
    {
        // we'll letter box then; scaling width to fill width, since
        // that's the smaller scale of the two possibilities
        targetSize.width = maxSize.width;

        // height is the original height adjusted proportionally
        // to match the proportional adjustment in width
        targetSize.height = 
                      (maxSize.width / sizeOfImage.width) * sizeOfImage.height;
    }
    else
    {
        // basically the same as the above, except that we pillar box
        targetSize.height = maxSize.height;
        targetSize.width = 
                     (maxSize.height / sizeOfImage.height) * sizeOfImage.width;
    }

    // images can be integral sizes only, so round up
    // the target size and width, then construct a target
    // rect that centres the output image within that size;
    // this all ensures sub-pixel accuracy
    CGRect targetRect;

    // store the original target size and round up the original
    targetRect.size = targetSize;
    targetSize.width = ceilf(targetSize.width);
    targetSize.height = ceilf(targetSize.height);

    // work out how to centre the source image within the integral-sized
    // output image
    targetRect.origin.x = (targetSize.width - targetRect.size.height) * 0.5f;
    targetRect.origin.y = (targetSize.height - targetRect.size.width) * 0.5f;

    // now create a CGContext to draw to, draw the image to it suitably
    // scaled and positioned, and turn the thing into a UIImage

    // get a suitable CoreGraphics context to draw to, in RGBA;
    // I'm assuming iOS 4 or later here, to save some manual memory
    // management.
    CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context  = CGBitmapContextCreate(
           NULL,
           targetSize.width, targetSize.height,
           8, targetSize.width * 4,
           colourSpace, 
           kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast);
    CGColorSpaceRelease(colourSpace);

    // clear the context, since it may currently contain anything.
    CGContextClearRect(context, 
                  CGRectMake(0.0f, 0.0f, targetSize.width, targetSize.height));

    // draw the given image to the newly created context
    CGContextDrawImage(context, targetRect, [srcImage CGImage]);

    // get an image from the CG context, wrapping it as a UIImage
    CGImageRef cgImage = CGBitmapContextCreateImage(context);
    UIImage *returnImage = [UIImage imageWithCGImage:cgImage];

    // clean up
    CGContextRelease(context);
    CGImageRelease(cgImage);

    return returnImage;
}

显然,我通过大量评论看起来很复杂,但它实际上只有23行。

答案 1 :(得分:1)

它们在帧缓冲存储器(即保持像素用于显示的存储器)方面不会花费太多,但是将未缩放的图像保持在存储器中仍将产生相当大的成本。如果1.5MB是压缩大小。这可能是(iOS使用大约4个字节*宽度*每个图像的高度来存储未压缩的UIImage s)。当你的应用程序进入后台时,这些图像与内核将执行的自动内存管理交互不良 - 后备存储在内存压力发生时被释放,但后备图像不是。

解决这个问题的最佳方法(如果你应该自己调整大小,存储较小的版本,并释放大版本)是使用VM Tracker通过Instruments运行你的应用程序。如果存储图像的区域过多,您将能够诊断它们,并选择适当的解决方案。您可能希望在iOS内存管理上查看WWDC 2011会话,其中详细介绍了图像内存使用情况,包括使用Instruments查找问题。

在优化之前,像往常一样,配置文件(或者,正如Apple可能会说的,仪器)!

答案 2 :(得分:1)

#import <ImageIO/ImageIO.h>
#import <MobileCoreServices/MobileCoreServices.h>

+ (UIImage *)resizeImage:(UIImage *)image toResolution:(int)resolution {
  NSData *imageData = UIImagePNGRepresentation(image);
  CGImageSourceRef src = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
  CFDictionaryRef options = (__bridge CFDictionaryRef) @{
                                                   (id) kCGImageSourceCreateThumbnailWithTransform : @YES,
                                                   (id) kCGImageSourceCreateThumbnailFromImageAlways : @YES,
                                                   (id) kCGImageSourceThumbnailMaxPixelSize : @(resolution)
                                                   };
  CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options);
  CFRelease(src);
  UIImage *img = [[UIImage alloc]initWithCGImage:thumbnail];
  return img;
}

答案 3 :(得分:0)

是的。你应该创建缩小版本的图像,将它们缓存到某个地方的磁盘,在图像视图中使用小版本,如果可以的话,卸载大版本。