iPhone中UIImage的内存分配和发布?

时间:2009-10-07 05:32:53

标签: iphone

我在iPhone中使用以下代码来获取较小的裁剪图像,如下所示:

- (UIImage*) getSmallImage:(UIImage*) img
{
    CGSize size = img.size;
    CGFloat ratio = 0;
    if (size.width < size.height) {
        ratio = 36 / size.width;
    } else {
        ratio = 36 / size.height;
    }
    CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height);

    UIGraphicsBeginImageContext(rect.size);
    [img drawInRect:rect];

    UIImage *tempImg = [UIGraphicsGetImageFromCurrentImageContext() retain];

    UIGraphicsEndImageContext();
    return [tempImg autorelease];
}

- (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect
{

    //create a context to do our clipping in
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef currentContext = UIGraphicsGetCurrentContext();

    //create a rect with the size we want to crop the image to
    //the X and Y here are zero so we start at the beginning of our
    //newly created context

    CGFloat X = (imageToCrop.size.width - rect.size.width)/2;
    CGFloat Y = (imageToCrop.size.height - rect.size.height)/2;


    CGRect clippedRect = CGRectMake(X, Y, rect.size.width, rect.size.height);
    //CGContextClipToRect( currentContext, clippedRect);



    //create a rect equivalent to the full size of the image
    //offset the rect by the X and Y we want to start the crop
    //from in order to cut off anything before them
    CGRect drawRect = CGRectMake(0,
                                 0,
                                 imageToCrop.size.width,
                                 imageToCrop.size.height);

    CGContextTranslateCTM(currentContext, 0.0, drawRect.size.height);
    CGContextScaleCTM(currentContext, 1.0, -1.0);
    //draw the image to our clipped context using our offset rect
    //CGContextDrawImage(currentContext, drawRect, imageToCrop.CGImage);


    CGImageRef tmp = CGImageCreateWithImageInRect(imageToCrop.CGImage, clippedRect);

    //pull the image from our cropped context
    UIImage *cropped = [UIImage imageWithCGImage:tmp];//UIGraphicsGetImageFromCurrentImageContext();
    CGImageRelease(tmp);
    //pop the context to get back to the default
    UIGraphicsEndImageContext();

    //Note: this is autoreleased*/
    return cropped;
}

我在cellForRowAtIndexPath中使用以下代码行来更新单元格的图像:

cell.img.image = [self imageByCropping:[self getSmallImage:[UIImage imageNamed:@"goal_image.png"]] toRect:CGRectMake(0, 0, 36, 36)];

现在当我添加这个表格视图并从导航控制器中弹出它时,我看到一个内存加息。我看到没有泄漏,但内存不断攀升。

请注意,每行的图像都会发生变化,我正在使用延迟初始化创建控制器,这是我创建或在需要时分配它。

我在互联网上看到许多人面临同样的问题,但非常罕见的好解决方案。我有多个视图使用相同的方式,我看到几乎内存在20-25视图转换中提升到4MB。

解决此问题的好方法是什么。

TNX。

5 个答案:

答案 0 :(得分:1)

您无法在EndImageContext之前从例程返回:

return UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

试试这个:

UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;

您不需要注释掉的保留或自动释放。

答案 1 :(得分:1)

[UIImage imageNamed:]导致内存泄漏,因为它使用了内部缓存图像。

  • 简单的方法是由程序员在外部缓存图像 为此,使用 -(UIImage*)thumbnailImage:(NSString*)fileName { UIImage *thumbnail = [thumbnailCache objectForKey:fileName]; if (nil == thumbnail) {
    NSString *thumbnailFile = [NSString stringWithFormat:@"%/%@", [[NSBundle mainBundle] pathForResource:fileName ofType:@"png"]]; //dont forget to set correct image type thumbnail = [UIImage imageWithContentsOfFile:thumbnailFile]; [thumbnailCache setObject:thumbnail forKey:fileName]; } return thumbnail; }

    在.h文件中声明NSMutableDictionary *thumbnailCache;

    使用可以像

    一样使用这个功能

    cell.img.image = [self imageByCropping:[self getSmallImage:[self thumbnailImage:@"goal_image"]] toRect:CGRectMake(0, 0, 36, 36)];

  • 清除应用程序共享缓存,即设置为nil

我认为这将解决你的问题。

答案 2 :(得分:1)

根据图像的大小,imageNamed:的使用可能是内存增长的原因。这不一定是个问题。 imageNamed:适用于经常加载相同图像并由缓存支持的代码。在iOS 3.0之前它有泄漏,但它们已经修复,如果你想利用缓存,我不知道有什么理由不使用这个API。

您应该通过Instruments运行代码,特别是Leaks模板。使用快照分析,您可以精确定位代码中的位置,以便在您不期望它们时增加内存占用,即使传统的泄漏分析错过了这些位置。 Bill Bumgarner wrote a post讨论了快照分析的使用。他使用Mac OS X应用程序作为他的例子,但这些技术同样适用于iOS应用程序。

答案 3 :(得分:0)

无法解决问题,但可能会导致问题:缓存缩略图。在36 x 36时,它们将非常小而无法记忆。这也应该提高性能,因为图形工作非常密集。

答案 4 :(得分:-1)

而不是使用autorelease来管理内存(据我所知,很少或根本没有保证何时会释放内存,只是它会最终分裂)您的用例代码行分为三个部分并自己管理内存。充其量可能是解决内存泄漏所必需的一切。至少像Instruments这样的工具可以从那里拿出它并向你展示可能产生内存泄漏的地方。

此外,[UIImage imageNamed:]可能很昂贵并自动释放图像。您可以使用相对简单的图像缓存机制替换该调用,该机制可以重用常用的请求图像并为您提升启动性能。