【问题标题】:Objective C Memory Crash, UIImageViewObjective C 内存崩溃,UIImageView
【发布时间】:2013-02-07 13:42:39
【问题描述】:

我的应用在 UIImageView 中分配并显示图像。这发生在 viewDidLoad 的 24 个 imageViews 上。这些图像是从 50 个图像的列表中随机分配的。视图控制器从主屏幕被推送到模态。第一次加载需要一段时间。如果我很幸运,该视图会第二次加载。第三次,它几乎总是崩溃。我尝试将图像大小调整为 200 像素左右。我尝试使用以下方式分配图像:

    image1 = [UIImage imageNamed:@"image1.png"];

    [self.imageView setImage: image1];

还有:

    NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"image1" ofType:@"png"];

    image1 = [[UIImage alloc] initWithContentsOfFile:imagePath];

第二个似乎只会让事情变得更糟。

我还尝试使用 Instruments 运行该应用,但它无法识别任何内存泄漏。

我真的不知道还能去哪里。这个应用程序代表了巨大的时间投资,我真的很想看到这个问题得到解决...... 非常感谢

【问题讨论】:

  • 您是否收到内存警告?
  • 是的,我会收到内存警告,然后下次尝试加载视图时,它会崩溃。
  • 崩溃是因为你加载的图片太多太大,内存超出了ios允许的范围
  • 那么,如果我将图像的宽度设置为 100 像素或更小,您认为我可以将所有 24 个图像都放在视图中吗?
  • 请确保您的尺寸尽可能小,最好确保长度或宽度不大于 2^n ,ios会将宽度或长度设置为 2^n ,比如100就是128,129就是256。而且可以少加个imageView试试

标签: objective-c memory uiimageview uiimage


【解决方案1】:

从磁盘加载较小版本图像的最有效方法是:使用 Image I/O 框架来请求您将显示的实际大小的缩略图,而不是使用 imageNamed:,通过打电话给CGImageSourceCreateThumbnailAtIndex。这是我书中的例子:

NSURL* url =
    [[NSBundle mainBundle] URLForResource:@"colson"
                            withExtension:@"jpg"];
CGImageSourceRef src =
    CGImageSourceCreateWithURL((__bridge CFURLRef)url, nil);
CGFloat scale = [UIScreen mainScreen].scale;
CGFloat w = self.iv.bounds.size.width*scale;
NSDictionary* d =
    @{(id)kCGImageSourceShouldAllowFloat: (id)kCFBooleanTrue,
     (id)kCGImageSourceCreateThumbnailWithTransform: (id)kCFBooleanTrue,
     (id)kCGImageSourceCreateThumbnailFromImageAlways: (id)kCFBooleanTrue,
     (id)kCGImageSourceThumbnailMaxPixelSize: @((int)w)};
CGImageRef imref =
    CGImageSourceCreateThumbnailAtIndex(src, 0, (__bridge CFDictionaryRef)d);
UIImage* im =
    [UIImage imageWithCGImage:imref scale:scale
                  orientation:UIImageOrientationUp];
self.iv.image = im;
CFRelease(imref); CFRelease(src);

要求 UIImageView 显示比 UIImageView 本身更大的图像是一种巨大的内存浪费,因为全尺寸图像的位图必须保存在内存中。 Image I/O 框架生成较小的版本,甚至无需将整个原始图像作为位图解压到内存中。

【讨论】:

    【解决方案2】:

    我曾经遇到过这个问题,来自常规网站的图像比我使用的视图大得多。如果我没记错的话,图像正在被解压缩到它们的全分辨率,然后适合图像视图,这会占用你的内存。在显示它们之前,我必须先将它们缩小到图像视图大小。添加 CoreGraphics.framework 并使用此类创建一个图像对象以与您的图像视图一起使用。我在网上找到了它,并对其进行了一些调整,以寻找相同的答案,但不记得在哪里,所以感谢发布原版的那个人,无论他们是谁。

    ImageScale.h

    #import <Foundation/Foundation.h>
    
    @interface ImageScale : NSObject
    
    + (UIImage*)imageWithImage:(UIImage*)sourceImage scaledToSize:(CGSize)newSize;
    
    @end
    

    ImageScale.m

    #import "ImageScale.h"
    
    @implementation ImageScale
    
    + (UIImage*)imageWithImage:(UIImage*)sourceImage scaledToSize:(CGSize)newSize
    {
        CGFloat targetWidth = newSize.width;
        CGFloat targetHeight = newSize.height;
    
        CGImageRef imageRef = [sourceImage CGImage];
        CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
        CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);
    
        if (bitmapInfo == kCGImageAlphaNone) {
            bitmapInfo = kCGImageAlphaNoneSkipLast;
        }
    
        CGContextRef bitmap;
    
        if (sourceImage.imageOrientation == UIImageOrientationUp ||  sourceImage.imageOrientation == UIImageOrientationDown) {
            bitmap = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
    
        } else {
            bitmap = CGBitmapContextCreate(NULL, targetHeight, targetWidth, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
    
        }
    
        if (sourceImage.imageOrientation == UIImageOrientationLeft) {
            CGContextRotateCTM (bitmap, M_PI_2); // + 90 degrees
            CGContextTranslateCTM (bitmap, 0, -targetHeight);
    
        } else if (sourceImage.imageOrientation == UIImageOrientationRight) {
            CGContextRotateCTM (bitmap, -M_PI_2); // - 90 degrees
            CGContextTranslateCTM (bitmap, -targetWidth, 0);
    
        } else if (sourceImage.imageOrientation == UIImageOrientationUp) {
            // NOTHING
        } else if (sourceImage.imageOrientation == UIImageOrientationDown) {
            CGContextTranslateCTM (bitmap, targetWidth, targetHeight);
            CGContextRotateCTM (bitmap, -M_PI); // - 180 degrees
        }
    
        CGContextDrawImage(bitmap, CGRectMake(0, 0, targetWidth, targetHeight), imageRef);
        CGImageRef ref = CGBitmapContextCreateImage(bitmap);
        UIImage* newImage = [UIImage imageWithCGImage:ref];
    
        CGContextRelease(bitmap);
        CGImageRelease(ref);
    
        return newImage; 
    }
    
    @end
    

    【讨论】:

    • 我没有选择使用较小的图像,如果你这样做是一个更好的选择顺便说一句。
    • 太棒了!很高兴听到其他人也有这个问题!我很高兴我现在不必废弃我的应用程序!谢谢!
    猜你喜欢
    • 2013-02-04
    • 1970-01-01
    • 2019-10-24
    • 2015-08-08
    • 1970-01-01
    • 2012-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多