从文档目录读取图像时内存泄漏

时间:2012-07-06 09:21:29

标签: iphone

我正在循环中从文档目录中读取图像。

for(iArrCount=0;iArrCount<[arrImages count];iArrCount++)
    {
UIButton *btnImage = [UIButton buttonWithType:UIButtonTypeCustom];
            btnImage.frame = CGRectMake(xRow, yRow, width, height);
            [btnImage addTarget:self action:@selector(imageDetails:) forControlEvents:UIControlEventTouchUpInside];
            btnImage.tag = iCount;
            if(iCount<[arrImages count])
            {


                NSString *workSpacePath=[[self applicationDocumentsDirectory] stringByAppendingPathComponent:[arrImages objectAtIndex:iCount]];
                [btnImage setBackgroundImage:[UIImage imageWithData:[NSData dataWithContentsOfFile:workSpacePath]] forState:UIControlStateNormal];
                [scrollImages addSubview:btnImage];
}
}  

执行此操作时,控件转到didRecieveMemoryWarning并且应用程序崩溃。如果我用资源文件夹中的图像替换图像,应用程序不会崩溃。为什么这样?

3 个答案:

答案 0 :(得分:2)

问题是您的按钮保持对全分辨率图像的引用。您需要做的是将图像缩小到按钮尺寸,并将缩小的图像设置为按钮背景。这样的事情可以解决问题:

在UIImage上创建一个类别......我们称之为UIImage + Scaler.h

// UIImage+Scaler.h
#import <UIKit/UIKit.h>

@interface UIImage (Scaler)
- (UIImage*)scaleToSize:(CGSize)size;
@end

实施:

// UIImage+Scaler.m
#import "UIImage+Scaler.h"

#define kBitsPerComponent 8
#define kBitmapInfo       kCGImageAlphaPremultipliedLast

- (UIImage*)scaleToSize:(CGSize)size
{
    CGBitmapInfo bitmapInfo = kBitmapInfo;
    size_t bytesPerRow = size.width * 4.0;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, size.width, 
                                   size.height, kBitsPerComponent, 
                                   bytesPerRow, colorSpace, bitmapInfo);

    CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
    CGContextDrawImage(context, rect, self.CGImage);

    CGImageRef scaledImageRef = CGBitmapContextCreateImage(context);
    UIImage* scaledImage = [UIImage imageWithCGImage:scaledImageRef];

    CGImageRelease(scaledImageRef);
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);

    return scaledImage;
}

好的,现在回到你的代码。像其他海报一样,你需要一个自动释放池。

CGSize buttonSize = CGSizeMake(width, height);

for(iArrCount=0;iArrCount<[arrImages count];iArrCount++)
{
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    UIButton *btnImage = [UIButton buttonWithType:UIButtonTypeCustom];
    btnImage.frame = CGRectMake(xRow, yRow, width, height);
    [btnImage addTarget:self 
                 action:@selector(imageDetails:)      
       forControlEvents:UIControlEventTouchUpInside];
    btnImage.tag = iCount;
    if(iCount<[arrImages count])
    {
        NSString *workSpacePath=[[self applicationDocumentsDirectory]  
                       stringByAppendingPathComponent:
                            [arrImages objectAtIndex:iCount]];
        UIImage* bigImage = [UIImage imageWithData:[NSData   
                             dataWithContentsOfFile:workSpacePath]];
        UIImage* smallImage = [bigImage scaleToSize:buttonSize];
        [btnImage setBackgroundImage:smallImage forState:UIControlStateNormal];
        [scrollImages addSubview:btnImage];
    }
    [pool drain]; // must drain pool inside loop to release bigImage
} 

希望这能解决问题。

答案 1 :(得分:0)

for循环放在自动释放池中:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for(...)
{
   ....
}
[pool release];

答案 2 :(得分:0)

使用NSAutoreleasePool。将代码保存在autoreleasepool中。

for(iArrCount=0;iArrCount<[arrImages count];iArrCount++)
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    ......
    ......
    [pool drain];
}