内存不断增加,然后应用程序崩溃时,滚动UITableview中显示图像从文档目录
我的要求是下载应用程序内存中的所有图像,并显示从本地(如果可用)。
下面是我的代码从本地访问图像,如果它不可用,那么它将下载然后显示。
[cell.imgProfilePic processImageDataWithURLString:cData.PICTURE];
我做了自定义的UIImageView
类
DImageView.h
#import <UIKit/UIKit.h> @interface DImageView : UIImageView @property (nonatomic, strong) UIActivityIndicatorView *activityView; - (void)processImageDataWithURLString:(NSString *)urlString; + (UIImage *)getSavedImage :(NSString *)fileName; @end
DImageView.m
#import "DImageView.h" #define IMAGES_FOLDER_NAME @"DImages" @implementation DImageView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { } return self; } - (void)dealloc { self.activityView = nil; [super dealloc]; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { [self initWithFrame:[self frame]]; } return self; } - (void)processImageDataWithURLString:(NSString *)urlString { @autoreleasepool { UIImage * saveImg =[DImageView getSavedImage:urlString]; if (saveImg) { @autoreleasepool { dispatch_queue_t callerQueue = dispatch_get_main_queue(); dispatch_async(callerQueue, ^{ @autoreleasepool{ [self setImage:saveImg]; } }); } } else { [self showActivityIndicator]; NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; dispatch_queue_t callerQueue = dispatch_get_main_queue(); dispatch_queue_t downloadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0); __block NSError* error = nil; dispatch_async(downloadQueue, ^{ @autoreleasepool { NSData * imageData = [NSData dataWithContentsOfURL:url options:NSDataReadingUncached error:&error]; if (!error) { dispatch_async(callerQueue, ^{ @autoreleasepool { UIImage *image = [UIImage imageWithData:imageData]; [self setImage:image]; [self hideActivityIndicator]; [self saveImageWithFolderName:IMAGES_FOLDER_NAME AndFileName:urlString AndImage:imageData]; } }); } } }); dispatch_release(downloadQueue); } } } - (void) showActivityIndicator { self.activityView = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; self.activityView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; self.activityView.hidesWhenStopped = TRUE; self.activityView.backgroundColor = [UIColor clearColor]; self.activityView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray; [self addSubview:self.activityView]; [self.activityView startAnimating]; } - (void) hideActivityIndicator { CAAnimation *animation = [NSClassFromString(@"CATransition") animation]; [animation setValue:@"kCATransitionFade" forKey:@"type"]; animation.duration = 0.4;; [self.layer addAnimation:animation forKey:nil]; [self.activityView stopAnimating]; [self.activityView removeFromSuperview]; for (UIView * view in self.subviews) { if([view isKindOfClass:[UIActivityIndicatorView class]]) [view removeFromSuperview]; } } - (void)saveImageWithFolderName:(NSString *)folderName AndFileName:(NSString *)fileName AndImage:(NSData *) imageData { @autoreleasepool{ NSFileManager *fileManger = [[NSFileManager defaultManager] autorelease]; NSString *directoryPath = [[NSString stringWithFormat:@"%@/%@",[DImageView applicationDocumentsDirectory],folderName] autorelease]; if (![fileManger fileExistsAtPath:directoryPath]) { NSError *error = nil; [fileManger createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&error]; } fileName = [DImageView fileNameValidate:fileName]; NSString *filePath = [[NSString stringWithFormat:@"%@/%@",directoryPath,fileName] autorelease]; BOOL isSaved = [imageData writeToFile:filePath atomically:YES]; if (!isSaved)DLog(@" ** Img Not Saved"); } } + (NSString *)applicationDocumentsDirectory { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil; return basePath; } + (UIImage *)getSavedImage :(NSString *)fileName { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; fileName = [DImageView fileNameValidate:fileName]; NSFileManager * fileManger = [[NSFileManager defaultManager] autorelease]; NSString * directoryPath = [[NSString stringWithFormat:@"%@/%@",[DImageView applicationDocumentsDirectory],IMAGES_FOLDER_NAME] autorelease]; NSString * filePath = [[NSString stringWithFormat:@"%@/%@",directoryPath,fileName] autorelease]; if ([fileManger fileExistsAtPath:directoryPath]) { UIImage *image = [[[UIImage imageWithContentsOfFile:filePath] retain]autorelease]; if (image) return image; else return nil; } [pool release]; return nil; } + (NSString*) fileNameValidate : (NSString*) name { name = [name stringByReplacingOccurrencesOfString:@"://" withString:@"##"]; name = [name stringByReplacingOccurrencesOfString:@"/" withString:@"#"]; name = [name stringByReplacingOccurrencesOfString:@"%20" withString:@""]; return name; } @end
一切工作正常,顺利滚动以及在后台的asyncImage下载。
问题是当我滚动UITableview
应用程序内存不断增加,并在一段时间后,我得到Receive memory waring
2/3时间然后应用程序崩溃。
当我使用AsyncImageView
类的时间内存不增加,它的工作正常。 但由于应用程序的要求,我保存所有的图像Document Directory
并显示它,如果它可用。
我已经尝试了@autoreleasepool
并release
一些variables,但没有得到成功。
我很感激,如果有任何人有解决scheme来pipe理内存pipe理。
**ARC is off in my application.**
UIImagePNGRepresentation可能会返回非自动释放对象 – 您可以尝试释放它,看看是否会导致崩溃。 显然你没有发布一些东西,除了图像表示之外没有其他的东西显得很明显。
其他一些评论:
-
使用ObjectAlloc工具在Instruments中运行应用程序,应该立即明白哪些对象没有被处理。 如果你不了解乐器,那么现在是时候学习它了。
-
你可以“追踪”对象,并在使用ObjectTracker进行交易时得到一个消息 – 但是它是为ARCdevise的,所以你可能需要调整它。 如果你使用它,你会看到一个消息,当你的每个对象是交易
-
当一个单元格完成表格视图时,可以接收一个委托方法告诉你这个,然后你可以释放(释放)和对象单元格保留
-
你对
downloadQueue
的使用是奇怪的 – 在你的实例中创build一个ivar,根据需要使用它,在dealloc中释放它 -
您将活动微调器隐藏在主队列上,但不要在主队列上启动它
-
您命令活动视图从其超级视图中删除自己,但然后在子视图中查找并尝试在其中删除它:
[self.activityView removeFromSuperview];
for (UIView * view in self.subviews) { if([view isKindOfClass:[UIActivityIndicatorView class]]) [view removeFromSuperview]; }
最后,乐器是你想要的。 你可以在这里阅读更多关于它,或只是谷歌,你一定会发现大量的博客阅读。
是的最后我解决了它。
问题中的代码现在工作正常。 但不release
一些对象和代码中的@autoreleasepool
块,在UITableView
滚动期间内存不断增加。
从Instrument
我发现在UILableView
和UIImageView
增加内存。 我使用自定义UITableViewCell
并在该文件我havnt实施dealloc
方法。 所以当我在UITableViewCell
.m
文件中实现dealloc
方法并release
& nil
所有对象。
之后, memory
不会增加在滚动TableView
和它的解决问题。
根据我的理解,你的“getSavedImage”方法有一个问题,你必须手动pipe理内存而不是“autorelease”,所以我的build议是使用
UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath] and also release it after use of it. means after '[self setImage:saveImg];' [saveImg release]
而不是这个。
[[UIImage imageWithContentsOfFile:filePath] retain];
'不要使用自动释放,因为它一直呆在内存,直到池不stream失',正因为如此,你有一个内存问题。