UIImage takes a lot of memory when loaded from file - ios

In my iPad app at one moment I load 100 images from Photo Stream using ALAsset and following code:
ALAsset *asset = [assets objectAtIndex:[sender tag]];
ALAssetRepresentation *representation = [asset defaultRepresentation];
UIImage *image = [[UIImage alloc] initWithCGImage:[representation fullScreenImage]
scale:1.0f
orientation:0];
And everything works perfectly. But when I cache it to the file system as JPEG files, and then load them again with UIImage *image = [UIImage imageWithContentsOfFile:fullPath], application crashes with Memory Warning, and I can see in the profiler that it really uses a lot of RAM.
Why is this happening?

One thing,
When you are loading the image from gallery, why not store the AssetURL, instead of the UIImage; that should take less space and increase speed.
When you need to show, use the thumbnail representation, perhaps?

Ok, it was my bad. I found the problem, and it comes out that I have memory problems in any case. ALAsset and imageWithContentsOfFile are working exactly the same.
Now I will try to find the way to reduce each image's size.

Related

imageWithContentsOfFile memory issue

My project is having image sharing functionality. In this functionality my app asks the user from which library you want to share.
I wrote below code to assign image, retrieved from Default library/Custom library.
Device default library
imgVwMediaFile.image = [UIImage imageWithCGImage:[asset thumbnail]; //(ALAsset *)asset
Custom library (images are at Documents/image/user)
imgVwMediaFile.image = [UIImage imageWithContentsOfFile:path];
//(NSString*)path
App displyas this images in collection view having custom cell.
When i select app custom library then images are retrieves from Documents directory ,but imagewithcontentofFile cosuming around 90 to 100 Mb memory.
In other case when i select app default libray, it is not cosuming more then 8 or 10 Mb memory.
I tried diffrent code from stack Q/A for custom library, but still memory issue is there.
-1-
CGImageRef iref = [[UIImage imageNamed:asset] CGImage] ;
imgVwMediaFile.image=[UIImage imageWithCGImage:iref];
iref=nil
-2-
NSData *imageData = [[NSData alloc] initWithContentsOfFile:path];
imgVwMediaFile.image=[UIImage imageWithData:imageData];
imageData=nil
-3-
imgVwMediaFile.image=[UIImage imageNamed:path];
So please guide me that, how can i load images from document dir ?
What are the best way to load images from document dir without increasing memory load ?
The problem is that yhe images you have saved to disk are large, so loading lots of the, to display in a collection takes a lot of memory. You use thumbnails from the built in library so you see a different result.
Ideally you would save a folder of thumbnails in your custom library and display those, then, when an image is selected, get the corresponding full size image to use (this is the approach basically all photo libraries use). Alternatively you can resize the images on-the-fly, but your scrolling is basically guaranteed to suck.
UIImage *img = [UIImage imageWithContentsOfFile:path];

iPhone app memory leak with UIImages in NSMutableArray

I have an NSMutableArray that contains images. I then have an image view that displays images from that array. However, I am getting a big memory leak each time it loads the image view. I am not sure how to correct that. I am using ARC in Xcode 5.0.2.
_image1 = [UIImage imageNamed:#"FirstImage.png"];
imagearray = [[NSMutableArray alloc] init];
[imagearray addObject:_image1];
_imageview1 setImage:[imagearray objectAtIndex:0]];
The memory leak issue might be due to the UIImage not getting nil. For that, you have to initialize UIImage with alloc and after adding it to the array, make it nil. You can prevent you memory leak in this way:
UIImage *image1 =[[UIImage alloc]initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"FirstImage" ofType:#"png"]];
[imagearray addObject:image1];
_imageview1 setImage:[imagearray objectAtIndex:0]];
image1 =nil;
Please let me kniw if it works. Thanks :)
From apple doc:
+ (UIImage)imageNamed: method looks in the system caches for an image object with the specified name and returns that object if it exists.
If a matching image object is not already in the cache, this method
loads the image data from the specified file, caches it, and then
returns the resulting object.
If you have an image file that will only be displayed once and wish to
ensure that it does not get added to the system’s cache, you should
instead create your image using imageWithContentsOfFile:. This will
keep your single-use image out of the system image cache, potentially
improving the memory use characteristics of your app.
So as a suggestion, if you replace the imageNamed: with imageWithContentsOfFile: to avoid caching, your memory footprint should improve

NSCoding UIImage to disk takes up huge amount of disk space and writes slowly

I am serializing UIImages to disk using NSKeyedArchiver.
UIImage conforms to NSCoding so serializes+deserializes properly but the resulting file is quite large causing performance issues.
I tested this by loading images from the ALAssetsLibrary taken on a standard iPhone5 camera to a UIImage and then serializing images to disk
UIImage *testImage = [asset defaultRepresentation]....
[NSKeyedArchiver archive:testImage ....]
The files were ~15MB and took over 1 second to write/load.
Then I tried serializing the UIImage by converting to NSData:
NSData *imageData = UIImageJPEGRepresentation(UIImage *image, 0....1); // tried most compression all the way to least compression
[NSKeyedArchiver archive:imageData....]
The resulting files were magnitude smaller (so faster to read and write)
What is the suggested way to save images? are the underlying images from the ALAssetsLibrary also taking 15MB on disk to store the images?
Should I be using PNG representation?

How to find UIImage Bottleneck

I have an app that uses UIImage objects. Up to this point, I've been using image objects initialized using something like this:
UIImage *image = [UIImage imageNamed:imageName];
using an image in my app bundle. I've been adding functionality to allow users to use imagery from the camera or their library using UIImagePickerController. These images, obviously, can't be in my app bundle, so I initialize the UIImage object a different way:
UIImage *image = [UIImage imageWithContentsOfFile:pathToFile];
This is done after first resizing the image to a size similar to the other files in my app bundle, in both pixel dimensions and total bytes, both using Jpeg format (interestingly, PNG was much slower, even for the same file size). In other words, the file pointed to by pathToFile is a file of similar size as an image in the bundle (pixel dimensions match, and compression was chosen so byte count was similar).
The app goes through a loop making small pieces from the original image, among other things that are not relevant to this post. My issue is that going through the loop using an image created the second way takes much longer than using an image created the first way.
I realize the first method caches the image, but I don't think that's relevant, unless I'm not understanding how the caching works. If it is the relevant factor, how can I add caching to the second method?
The relevant portion of code that is causing the bottleneck is this:
[image drawInRect:self.imageSquare];
Here, self is a subclass of UIImageView. Its property imageSquare is simply a CGRect defining what gets drawn. This portion is the same for both methods. So why is the second method so much slower with similar sized UIImage object?
Is there something I could be doing differently to optimize this process?
EDIT: I change access to the image in the bundle to imageWithContentsOfFile and the time to perform the loop changed from about 4 seconds to just over a minute. So it's looking like I need to find some way to do caching like imageNamed does, but with non-bundled files.
UIImage imageNamed doesn't simply cache the image. It caches an uncompressed image. The extra time spent was not caused by reading from local storage to RAM but by decompressing the image.
The solution was to create a new uncompressed UIImage object and use it for the time sensitive portion of the code. The uncompressed object is discarded when that section of code is complete. For completeness, here is a copy of the class method to return an uncompressed UIImage object from a compressed one, thanks to another thread. Note that this assumes data is in CGImage. That is not always true for UIImage objects.
+(UIImage *)decompressedImage:(UIImage *)compressedImage
{
CGImageRef originalImage = compressedImage.CGImage;
CFDataRef imageData = CGDataProviderCopyData(
CGImageGetDataProvider(originalImage));
CGDataProviderRef imageDataProvider = CGDataProviderCreateWithCFData(imageData);
CFRelease(imageData);
CGImageRef image = CGImageCreate(
CGImageGetWidth(originalImage),
CGImageGetHeight(originalImage),
CGImageGetBitsPerComponent(originalImage),
CGImageGetBitsPerPixel(originalImage),
CGImageGetBytesPerRow(originalImage),
CGImageGetColorSpace(originalImage),
CGImageGetBitmapInfo(originalImage),
imageDataProvider,
CGImageGetDecode(originalImage),
CGImageGetShouldInterpolate(originalImage),
CGImageGetRenderingIntent(originalImage));
CGDataProviderRelease(imageDataProvider);
UIImage *decompressedImage = [UIImage imageWithCGImage:image];
CGImageRelease(image);
return decompressedImage;
}

UIImage from NSData in UITableView - performance issue

I am storing images from Photos Album in my app documents directory as NSData and than displaying them in UITableView. I have problem with performance. It takes a good few seconds to save image into app directory and I have same problem when than loading them into TableView. This is my code to store images:
//Convert UIImage to NSData
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(image)];
//Save image to app documents directory
NSError *error;
[imageData writeToFile:fullImagePath options:NSDataWritingAtomic error:&error];
That is how I load them into UITableView:
NSData *imageData = [NSData dataWithContentsOfFile:path];
UIImage *myImage = [UIImage imageWithData:imageData];
cell.imageView.image = myImage;
What may cause these performance issues? Is it any other way to store and retrieve images from app documents directory?
Two approaches:
First you might consider scaling down the images before you save them, or save an additional smaller copy for display in the table view. It depends how good images you need - presumably for the table view not as large as full scale pictures with MB of data. Actually, the images will also look better if they are properly scaled. This by itself should take care of the delays.
Second, you might consider loading the images asynchronously. Maintain a mutable array of images to be downloaded. Create a singleton that does the download and notifies the table view when finished. Set cell.imageView.image in the notification (or delegate) callback.

Resources