My Requirement is download all images in application memory and display it from local if its available.
Below is my code to access image from local and if its not available then it will download then display.
[cell.imgProfilePic processImageDataWithURLString:cData.PICTURE];
I have made custom UIImageView
class
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
Everything is working fine with smooth scrolling as well as asyncImage download in background.
The issue is when i scroll UITableview
application memory is continuously increase and after some time i got Receive memory waring
2/3 time then application crash.
When i use AsyncImageView
class that time memory not increase and its working fine. But due to app requirement i saved all images to Document Directory
and display from it if its available.
i have tried with @autoreleasepool
and release
some variable but not getting success.
I appreciated if any one have the solution to manage memory management.
**ARC is off in my application.**
It's possible that UIImagePNGRepresentation returns non-autoreleased object - you can try to release it and see if that results in a crash. Obviously you are not releasing something, but nothing other than the image representation appears obvious.
A few other comments:
run your app in Instruments, using the ObjectAlloc tool, and it should be immediately obvious what objects are not dealloced. If you don't know Instruments, well, its time now to learn it.
you can 'track' objects and get a message when they are dealloced using ObjectTracker - however it was designed for ARC so you may need to tweak it. If you use it you would see a message when each of your objects are dealloced
when the table view is done with a cell, there is a delegate method that you can receive that tells you so, and you can then nil (release) and objects the cell retains
your use of downloadQueue
is bizarre - create it once in your instance as an ivar, use it as you need, and in dealloc release it
you hide the activity spinner on the main queue, but don't start it on the main queue
you command the activity view to remove itself from its superview, but then look for in in the subviews and try to remove it there:
[self.activityView removeFromSuperview];
for (UIView * view in self.subviews)
{
if([view isKindOfClass:[UIActivityIndicatorView class]])
[view removeFromSuperview];
}
In the end, Instruments is what you want. You can read up more about it here, or just google and you will surely find a slew of blogs to read.
Yes Finally i have resolved it.
The code which is in Question is working fine now. but Without release
some objects and @autoreleasepool
block which is in code, memory was increase continuously during scroll UITableView
.
From the Instrument
i found that memory increase in UILableView
and UIImageView
. I am using Custom UITableViewCell
and in that file i havnt implement dealloc
method. So When i have implement dealloc
method in UITableViewCell
.m
file and release
& nil
all object.
After that memory
not increase during scroll TableView
and its Resolved the issue.
As per my Understanding there is an issue in your "getSavedImage" Method you have to manage memory Manually instead of 'autorelease' so as My suggestion is use
UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath]
and also release it after use of it. means after '[self setImage:saveImg];'
[saveImg release]
instead of this.
[[UIImage imageWithContentsOfFile:filePath] retain];
'Don't Use Autorelease because it has staying in memory until pool not drain' and just because of this you got an memory issue.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.