Does UIImageView cache images? - ios

Probably I'm gonna ask the same question which was asked by other person (But it has no responses): Speed up first UIImageView animation (force cache the images)
But, My short question is:
I have 60 images in resources, in timeinterval loop I'm gonna animate that images, each time setting to UIImageView.image the n'th image from resouce.
The problem is: first animation is bad! When I loop all images again in same UIImageView, animation is perfect. Can we pre cache images in UIImageView?
EDIT: Or maybe we can make some tricks, to make animation smooth?

The method
[UIImage imageNamed:#""]
caches the image. The UIImageView doesn't. I had a problem in an app with a lot of images that was crashing due to low memory.
To fix if I changed to [UIImage imageWithContentsOfFile:#""] that does not caches the image.
To pre-cache the image you can simply call [UIImage imageNamed:#""] for all images you want in the init method. But if you receive a memory warning the images gonna be deallocated.

UIImageView does not cache the image, as [UIImage imageNamed:#""] does. Unfortunately, if you have a lot of images, imageNamed will crash your application because it runs out of memory.
You can pre-load all of the images in an NSArray using [UIImage imageWithContensOfFile:#""].
Once you have the array, you can do what you want!

No, UIImageView does not cache images. image property declared as retain, so when you set new image, then imageView send release message to old image and retain to new one.
The easiest way to animate UIImageView is to set array of images to property animationImages and call startAnimating method
imageView.animationImages = [NSArray arrayWithObjects:[UIImage imageNamed:#"1.png"], ..., nil];
imageView.animationDuration = 2.0f;
[imageView startAnimating];

Related

I have to download a large number of big size images and show in table view?

I am getting memory warning when loading large images, i have to cache the images also so that if the user will scroll up that image should be present. I am using SDWebImage Library.
cell!.productImageView?.sd_setImageWithURL(url)
According to your scenario I have two suggestions:
1. Generally recommended is that we can upload small size images on server so that we can avoid memory problems. A thumbnail or a small dimension sized image is considered if we are showing the images in a UITableView.However we can show larger image when we tap on a certain small image in UITableView and go to a detail view controller.
2. Secondly you can download the images and resize them and then use NSCache class to cache them rather using SDWebImage. As in your case imageWithContentsOfFile can't be used because you are downloading the images from some URL.However after download you can use imageWithContentsOfFile or you can resize images and use your own NSCache.
What are you using for display image on image view .UIImage imageNamed is maintain cache itself.
Please use below code.
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"imageName" ofType:#"png"]];
This will helpful to you for manage memory consumptions.
Try this code.
NSString *thumbnailImage = objectname.thumbnailUrl;
[cell.productImageView sd_setImageWithURL:[NSURL URLWithString:thumbnailImage]];

iOS: Instruments shows imageio_png_data is 300x larger in size than its actual image size

I have an image that is only 28KB in size:
I'm adding it to my view using this code:
UIImageView *background = [UIImageView new];
background.frame = CGRectMake(0, 0, 1080, 1920);
background.image = [UIImage imageNamed:#"Submit.png"];
[self.view addSubview:background];
Now I'm profiling with Instruments Allocation and "Marking Generation" right before and right after the image is allocated:
Instruments indicates that it took 7.92MB to load the image into memory.
I'm seeing the same issue with other images as well.
Why is ImageIO_PNG_Data at 7.92MB when the image is only 28KB in size?
#matt and #dan really did a good job of explaining why an uncompressed image should take up literally 300X memory of the actual PNG image size to display on the screen. What makes this issue worse is that the iOS caches these images and does NOT release them from cache EVER, even on memory warnings.
So here's a way to prevent image caching on iOS to save up a ton of memory, just use imageWithContentsOfFile instead of imageNamed:
Replace:
background.image = [UIImage imageNamed:#"Submit.png"];
With:
background.image = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] bundlePath] stringByAppendingString:#"/Submit.png"]];
and now the ImageIO_PNG_Data's will be released when the view controller is dismissed.
It's all right here:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImage_Class/#//apple_ref/occ/clm/UIImage/imageNamed:
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.
It's because a PNG is compressed data describing what the image looks like, so a PNG that is nothing but a solid color is tiny because it is easy to describe. But the bitmap is the bitmap - just a grid of pixels - and depends purely on the dimensions of the image (which, in your case, is immense).

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

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;
}

Load large UIImages asynchronously

I have an NSManagedObject which has pictures that are stored somewhere like /var/mobile/Applications/.../.../uniqueIDforNSMO/Pictures/
I have no problem getting these pictures off the disk by finding them based on the NSMO's uniqueID, I have a DataController that will pull them for me, and that is very performant. But I run into issues when I try to add these pictures to a view, the UI becomes blocked. I suspect the problem is that these images are very high resolution (they are images from the iPad camera roll).
Displaying 5 images takes about 3 seconds, leaving the UI blocked. Displaying even just 2 images blocks the damn UI. Here's how I add them, on a background thread:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage *image = [self.photos objectAtIndex:index];
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = image;
});
});
If I set the imageView.image without dispatching it takes even longer.
Could the problem be that the images are so large, while the cell's imageViews are only 150x150? Or is it because I only have a reference to the image at first, so the realization of the image is the slow part?
Can anyone suggest anything here? I have tried resizing the images before they are returned in the array and that did not help.
The problem is that the images are being lazily loaded - UIImage only loads the image into memory when it needs to be drawn. What you can do is eagerly load the image on a background thread:
Create a CGBitmapContextRef using UIGraphicsBeginImageContext
Draw the image into the context
Get a new image from the context using UIGraphicsGetImageFromCurrentImageContext
Pass the image back to the main thread
As they are high-resolution images, I would suggest that you should make persistent thumbnails cache for that. Generating thumbnail real-time every time would waste too much CPU time unnecessarily.

Resources