我遇到了一个问题,那就是从内存(1MB〜5MB)中看不到相对较大的图像。当用户滚动浏览一组图像时,以下代码块被调用。大约15张图片后,应用程序将崩溃。有时候,“didReceiveMemoryWarning”被调用,有时它不会 - 应用程序只会崩溃,停止,退出调试,而不会在任何代码行中停止 - 什么都不会。我认为这是设备内存不足时发生的情况?另一个担心是'dealloc'似乎永远不会被调用到子类“DownloadImageOperation”中。有任何想法吗?在NSOperation中设置UIImage时发生内存泄漏
获取和设置图像:
//Calling this block of code multiple times will eventually cause the
// application to crash
//Memory monitor shows real memory jumping 5MB to 20MB increments in instruments.
//Allocations tool shows #living creeping up after this method is called.
//Leaks indicate something is leaking, but in the 1 to 5 kb increments. Nothing huge.
DownloadImageOperation * imageOp = [[DownloadImageOperation alloc] initWithURL:imageURL localPath:imageFilePath];
[imageOp setCompletionBlock:^(void){
//Set the image in a UIImageView in the open UIViewController.
[self.ivScrollView setImage:imageOp.image];
}];
//Add operation to ivar NSOperationQueue
[mainImageQueue addOperation:imageOp];
[imageOp release];
DownloadImageOperation定义:
.h文件中
#import <Foundation/Foundation.h>
@interface DownloadImageOperation : NSOperation {
UIImage * image;
NSString * downloadURL;
NSString * downloadFilename;
}
@property (retain) UIImage * image;
@property (copy) NSString * downloadURL;
@property (copy) NSString * downloadFilename;
- (id) initWithURL:(NSString *)url localPath:(NSString *)filename;
@end
.m文件
#import "DownloadImageOperation.h"
#import "GetImage.h"
@implementation DownloadImageOperation
@synthesize image;
@synthesize downloadURL;
@synthesize downloadFilename;
- (id) initWithURL:(NSString *)url localPath:(NSString *)filename {
self = [super init];
if (self!= nil) {
[self setDownloadURL:url];
[self setDownloadFilename:filename];
[self setQueuePriority:NSOperationQueuePriorityHigh];
}
return self;
}
- (void)dealloc { //This never seems to get called?
[downloadURL release], downloadURL = nil;
[downloadFilename release], downloadFilename = nil;
[image release], image = nil;
[super dealloc];
}
-(void)main{
if (self.isCancelled) {
return;
}
UIImage * imageProperty = [[GetImage imageWithContentsOfFile:downloadFilename andURL:downloadURL] retain];
[self setImage:imageProperty];
[imageProperty release];
imageProperty = nil;
}
@end
获取图像类
个.m文件
+ (UIImage *)imageWithContentsOfFile:(NSString *)path andURL:(NSString*)urlString foundFile:(BOOL*)fileFound {
BOOL boolRef;
UIImage *image = nil;
NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
if (image==nil) {
boolRef = YES;
image = [UIImage imageWithContentsOfFile:[[AppDelegate applicationImagesDirectory] stringByAppendingPathComponent:[path lastPathComponent]]];
}
if (image==nil) {
boolRef = YES;
image = [super imageWithContentsOfFile:path];
}
if (image==nil) {
//Download image from the Internet
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setTimeOutSeconds:120];
[request startSynchronous];
NSData *responseData = [[request responseData] retain];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSData *rdat = [[NSData alloc] initWithData:responseData];
[responseData release];
NSError *imageDirError = nil;
NSArray *existing_images = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[path stringByDeletingLastPathComponent] error:&imageDirError];
if (existing_images == nil || [existing_images count] == 0) {
// create the image directory
[[NSFileManager defaultManager] createDirectoryAtPath:[path stringByDeletingLastPathComponent] withIntermediateDirectories:NO attributes:nil error:nil];
}
BOOL write_success = NO;
write_success = [rdat writeToFile:path atomically:YES];
if (write_success==NO) {
NSLog(@"Error writing file: %@",[path lastPathComponent]);
}
image = [UIImage imageWithData:rdat];
[rdat release];
}
return image;
}
道歉这个庞大的代码块。我真的不知道问题出在哪里,所以我尽量保持包容。谢谢阅读。
您能否在您的项目中使用ARC?它通常简化了内存管理。 – xyzzycoder
不幸的是,这不是使用ARC。这个项目在iOS 5之前开始。我很想找到一些方法来转换它。 – Erracity
@Erracity - 我认为转向ARC确实值得,即使第一次这样做需要一点努力。它可以让你摆脱内存管理的杂草,并消除了很多简单的泄漏。你仍然需要使用'block_mageOp'技巧的'__weak'变体,以避免完成块中的保留周期,但是所有的手动调用''__weak DownloadImageOperation * weakImageOp = imageOp;''保留'和'释放'走开。 – Rob