La memory aumenta continuamente y luego se bloquea la aplicación cuando muestro la image del directory del documento durante el desplazamiento UITableview

Mi requisito es download todas las imágenes en la memory de la aplicación y mostrarla desde local si está disponible.

A continuación se muestra mi código para acceder a la image local y, si no está disponible, se downloadá y luego se mostrará.

[cell.imgProfilePic processImageDataWithURLString:cData.PICTURE]; 

He hecho una class UIImageView personalizada

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 

Todo funciona bien con un desplazamiento suave y con la descarga de AsyncImage en segundo plano.

El problema es que cuando UITableview memory de la aplicación UITableview aumenta continuamente y, después de un time, UITableview memory de Receive memory waring 2/3 y luego la aplicación falla.

Cuando AsyncImageView class AsyncImageView , la memory de time no aumenta y funciona bien. Pero debido al requisito de la aplicación, guardé todas las imágenes en el Document Directory y la visualizé si está disponible.

He intentado con @autoreleasepool y release alguna variable pero no logro el éxito.

Aprecio si alguien tiene la solución para administrar la gestión de la memory.

  **ARC is off in my application.** 

Es posible que UIImagePNGRrepresentación devuelva object no autoelevado; puede intentar liberarlo y ver si eso resulta en un locking. Obviamente, no estás liberando algo, pero nada más que la representación de la image parece obvio.

Algunos otros comentarios:

  • ejecute su aplicación en Instruments, usando la herramienta ObjectAlloc, y debe ser obvio inmediatamente qué objects no están desalojados. Si no conoces Instrumentos, bueno, es hora de aprenderlo.

  • puede "rastrear" los objects y get un post cuando se desasignan utilizando ObjectTracker ; sin embargo, fue diseñado para ARC, por lo que puede necesitar modificarlo. Si lo usa, verá un post cuando cada uno de sus objects se desalinea

  • cuando la vista de tabla se realiza con una celda, hay un método de delegado que puede recibir que lo indica, y luego puede recuperar (liberar) y los objects que retiene la celda

  • su uso de downloadQueue es extraño: créelo una vez en su instancia como ivar, úselo según lo necesite y, en su defecto, libérelo

  • oculta el spinner de actividad en la queue principal, pero no lo inicie en la queue principal

  • usted ordera la vista de actividad para que se quite de su vista supervista, pero luego busca en las subvistas e intenta eliminarlo allí:

[self.activityView removeFromSuperview];

 for (UIView * view in self.subviews) { if([view isKindOfClass:[UIActivityIndicatorView class]]) [view removeFromSuperview]; } 

Al final, Instruments es lo que quieres. Puede leer más sobre esto aquí, o simplemente google y seguramente encontrará una gran cantidad de blogs para leer.

Sí, finalmente lo he resuelto.

El código que está en Pregunta funciona bien ahora. pero Sin la release algunos objects y el bloque @autoreleasepool que está en código, la memory se incrementó continuamente durante el desplazamiento UITableView .

Desde el Instrument encontré que el aumento de memory en UILableView y UIImageView . Estoy usando UITableViewCell personalizado y en ese file no dealloc implementado el método dealloc . Entonces, cuando implemento el método dealloc en el file UITableViewCell .m y release & nil todos los objects.

Después de que la memory no aumente durante el desplazamiento de TableView y se TableView el problema.

Según mi entendimiento, hay un problema en su método "getSavedImage" que tiene que administrar la memory manualmente en lugar de "autorelease" para que mi sugerencia sea usar

 UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath] and also release it after use of it. means after '[self setImage:saveImg];' [saveImg release] 

en lugar de esto.

 [[UIImage imageWithContentsOfFile:filePath] retain]; 

'No use Autorelease porque se ha quedado en la memory hasta que no se drene el grupo' y solo por esto tuvo un problema de memory.