user2724028
user2724028

Reputation: 604

Memory Leak from UIImageView

I currently working on a personal project in iOS7, and I must display several images on a Galarie scroll view. To do this I created a UIImage then I insert it in a UIImageView. I stock all my UIImageView in a NSMutableArray. I show all the pictures on the UIScrollView.

With the test I could perform, the memory used can go over 500 MB.

How can I optimize memory? How the camera base application it happens to you to display over 1000 photos?

Thank you in advance. Cordially.

Upvotes: 1

Views: 534

Answers (4)

Usman Nisar
Usman Nisar

Reputation: 3081

Simple solution is that to save original image to directory and assign resized image to scrollview. This solution will make you able to add greater number of images to scrollview with minimal usage of memory. Here is the sample code

-(IBAction)selectImageBtnClicked:(id)sender {

UIImagePickerController * picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:picker animated:YES completion:nil];
[picker release]; }

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

[picker dismissViewControllerAnimated:YES completion:nil];
[[picker parentViewController] dismissViewControllerAnimated:YES 

completion:nil];

UIImage *pTakenImage = [info objectForKey:UIImagePickerControllerEditedImage];
if (!pTakenImage)
    pTakenImage = [info objectForKey:UIImagePickerControllerOriginalImage];

[self performSelectorOnMainThread:@selector(proceedFURTHER:) 

withObject:pTakenImage waitUntilDone:NO]; }

-(void) proceedFURTHER : (UIImage*)pTakenImage { UIImage *pResizedImage = [self resizeImageToMaxSize:640.0 anImage:pTakenImage];

[self saveOriginalImageToDir:pTakenImage];

//add pResizedImage to your scrolview here

[self.navigationController popViewControllerAnimated:YES]; }

-(UIImage*)resizeImageToMaxSize:(CGFloat)max anImage:(UIImage*)anImage {

NSData * imgData = UIImageJPEGRepresentation(anImage, 1);
CGImageSourceRef imageSource = 

CGImageSourceCreateWithData((CFDataRef)imgData, NULL); if (!imageSource) return nil;

CFDictionaryRef options = 

(CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:

(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform,

(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageIfAbsent,

(id)[NSNumber numberWithFloat:max], (id)kCGImageSourceThumbnailMaxPixelSize, nil];

CGImageRef imgRef = 

CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options);

UIImage* scaled = [UIImage imageWithCGImage:imgRef];

CGImageRelease(imgRef);
CFRelease(imageSource);

return scaled; 

}

-(NSString*)getOriginalImageDirectoryPath {

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);

NSString *documentsPath = [paths objectAtIndex:0];
NSString *filePath = 

[documentsPath stringByAppendingPathComponent:@"scaledimage.png"];

return filePath; }

-(void) saveOriginalImageToDir :(UIImage*)image {

NSString *filePath = [self getOriginalImageDirectoryPath];

if([[NSFileManager defaultManager] fileExistsAtPath:filePath])
    [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];

NSData *data = UIImagePNGRepresentation(image);

[data writeToFile:filePath atomically:YES];
data = nil; }

Upvotes: 0

Sam B
Sam B

Reputation: 27598

I ran into this exact same problem couple of years ago when I used full size pictures in my UIImageViews. My app kept running out of memory on actual iPhone 4. For some reason it worked fine on iPhone simulator.

You must reduce your original images down using "UIImage+Resize" to show preview images in your UIScrollView. When user clicks on one of the images you can then show them a bigger/full version.

Download it from here.

CGSize buttonSize = CGSizeMake(100, 100);

UIImage * newImage = [[UIImage alloc] initWithContentsOfFile: pathToImage];
if(newImage)
{
    // this "resizedimage" image is what you want to pass to setImage
    UIImage * resizedImage = [newImage resizedImage: buttonSize interpolationQuality: kCGInterpolationLow];
}

Upvotes: 0

Bruno
Bruno

Reputation: 109

UICollectionView is more appropriate for your problem!

UICollectionView is like UITableView, only loads cells displayed on screen.

UICollectionView is a scrollview, but with memory management.

Upvotes: 1

Putz1103
Putz1103

Reputation: 6211

You need to set up lazy loading based on the scrollview location. Load only three times the visible screen (or less, depending on memory need) and implement the UIScrollViewDelegate function scrollviewDidScroll: to listen for scrolling events.

Inside scrollViewDidScroll you are going to want to search your array of images (it should be an array of locations and file names for best memory relief). If the scrollview is getting close to your image location then load it and add it to screen. If something was already on screen but is now far enough to be off screen and unloaded then remove it from the scrollview and release the object (or better, re-use it for the next image load).

Look into PDFKitten. They do lazy loading of PDF Pages. Your Images could be implemented the exact same way.

Upvotes: 1

Related Questions