How does UIImage work in low-memory situations? - iphone

According to the UIImage documentation:
In low-memory situations, image data may be purged from a UIImage object to free up memory on the system.
Does anyone know how this works? It appears that this process is completely transparent and will occur in the background with no input from me, but I can't find any definitive documentation one way or the other.
Second, will this data-purge occur when the image is not loaded by me? (I'm getting the image from UIImagePicker).
Here's the situation: I'm taking a picture with the UIImagePickerController and and immediately taking that image and sending it to a new UIViewController for display. Sending the raw image to the new controller crashes my app with memory warnings about 30% of the time. Resizing the image takes a few moments, time that I'd rather not spend if there's a 3rd option available to me.

I think this is the answer. In the documentation for initWithContentsOfFile: it says:
This method loads the image data into memory and marks it as purgeable. If the data is purged and needs to be reloaded, the image object loads that data again from the specified path.
None of the other methods in UIImage mention purging, so it appears that initializing a new image from a file is the only way to get this low memory behavior.

In answer to your second question: Save it to a file, and then use:
[NSData dataWithContentsOfMappedFile:]
to do the resizing. Using a files as intermediates, is rather slow though.

Related

iOS4 calling ImageNamed: still leak or cause memory issue?

So apparently, my app crashes on ipod 2nd generation due to low memory issue. What I do was calling image on each view within scrollView + pageControl when user scrolls. And app crashed when it reached a particular point after got memory warning. I tried to free up view when I got warning but it still caused crash.
I googled about ImageNamed: and apparently there was issue within this api call, but most article said it was fixed in recent iOS version.
I fixed this problem with calling image imageWithContentOfFile instead imageNamed, but I'm wondering if ImageNamed still causes memory leak or not free up when it view is released.
imageNamed: doesn't cause a leak, but it is frequently misunderstood which is what leads to memory issues when it's used. It caches the uncompressed image after it is loaded, which means there are immediately 2 copies of that image in memory. If you use it for small, frequently used images (such as icons), this is great because the runtime doesn't have to fetch the file off disk - it's already available in the cache. Where this gets users into trouble is when they use imageNamed: to load a large image, say a 4MP image taken with a camera. That image takes up quite a bit of memory: 4 million pixels, types 4 bytes per pixel = 16MB of memory, TWICE. If you use that method to load images for your slideshow, photo sharing, camera app, or whatever, it adds up real fast.
So if those features don't fit what you need, use one of the other UIImage loading methods. You users will thank you.
Note: This information comes from the Apple Engineer which presented the UIKit rendering session (#121 I think it was). Hopefully my notes are correct :)

Memory is increasing all the time in navigation based iphone app

I have a navigation based App with 5 ViewControllers. After inspecting the memory allocation with instruments i found out that memory is increasing permanently. The app starts up with 2 MB and after navigating through all 5 Navigationcontrollers it grows up to 10 MB and counting...
For every allocated object there is a corresponding release in my code (in dealloc or somewhere else), so obviously there are no memory leaks. Instruments also tells me that no memory leaks could be found.
How can I solve this memory problem? At some point of time, after navigating through the views forward and backward an out of memory warning occurs and the background image disappears (I do not deallocate the image so the iphone does it on its own).
How can i determine the source of the "memory leak" problem? Is it possible that images are cached somewhere and hold in memory as long as the app is alive?
I always alloc images like this:
UIImage *kaufpreisImage = [[UIImage alloc] initWithContentsOfFile: [[NSBundle mainBundle] pathForResource:#"kaufpreis_background_green18px" ofType:#"png"]];
The images are under the Resource folder.
I would very much appreciate your help! I can't find a way out of this!
Thank you very much in advance
Regards Phil
Edit:
The only problem remaining is when I try to send an email. I want to send an email which contains multiple html tables and images inside the email body. The images are base64 encoded. After sending multiple mails I recieve an out of memory warning, although I dealloc all the stuff (images, Numbers and so on) inside the sendMail() method.
Does anyone know if sending base64 encoded images leads to problems? Can anyone give me a hint how I can send images inside the emailbody (e.g. as background image inside a html table like style="background-url(data:image/png;base64,%#)")? To clearify, this works. The images are sent to the Client (tested on MacOS) but sometimes the memory problem occurs...
Thank you very much
You need to release those images once you take ownership of them.
Maybe you shall try the 'Heapshot' function in the Allocation tool. Simply take a 'Mark Heap' when your first controller is started then navigate on and again back. Take another heapshot. Repeat this process 8-10 times. In the heapshots list you shall see that some memory has been allocated between an heapshot and the following one (otherwise if the amount is small and tends to zero it is normal), try to inspect it in order to check if you allocate something that remains alive.
You are responsible for releasing the instances of UIImage if you have used [[UIImage alloc] init...] to create them.
If you are loading images from the main bundle, try using +(UIImage *)imageNamed:(NSString *)name. This UIImage returned is returned autoreleased, so you don't have to release, and there is the upside that UIKit handles caching when using the imageNamed method.

UIImagePickerController and the need to save the UIImage asap vs. exploiting the file backing

I've read uiimagepickercontroller uiimage memory and more and other relevant questions, but I can't get my head around one thing, and I wonder if there are people around here with experience on this particular aspect.
In my app I let the user select an image from his library, ultimately resulting in an upload. (An interesting thing here, is that the images in there may originate from 12-megapixel high quality camera's, since e.g. iTunes happily syncs them into the phone.)
For various reasons, I UIImageJPEGRepresentation the thing right away to a locally stored file.
Without much thought, I hung on to the UIImage returned by the picker.
In Instruments, on the simulator, I see that the UIImage returned by the UIImagePickerController releases the memory. Does this indeed mean it's being backed by the file in the library, which we cannot access?
Does this also mean, that the advice in the answer linked to above, to store the image right away when needing the full resolution, only leads to additional overhead? (at least for the pictures from the library)
Furthermore, an image taken with the camera, may or may not have some internal backing, which I haven't investigated yet (Why can't the simulator just use my iSight?!). If not, it would surely be a memory hog and the first thing to do would be an UIImageJPEGRepresentation followed by an UIImage imageWithContentsOfFile: to enable the backing, which would come at the cost of quite a delay.
Anyone any thoughts?

Why do I not get low memory issues until images are draw on the screen?

I am able to load over 200 UIImage objects into a NSMutableDictionary without any memorry warning issues.
When I start displaying them on the screen (after about showing 10-20 images) I get low memory warnings and an eventual crash.
Only about 8 images are displayed at anyone time.
Does it take additional memory to actually draw a UIImage on the screen?
No memory leaks are showing up and i've reviewed code for leaks many many times.
Its probable that you initially create a link to the image, the only data that is actually read at this time are dimensions and image type (in short), the rest of the data is usually not needed until requested usually from a background process i.e. displayed on screen. When it is displayed the actual image data is downloaded from the filepath and decoded according to its image type, it is then cached so it doesn't have to be downloaded again, the caching takes a lot of memory plus if your using double/triple buffering there's extra memory required for the off screen drawing.
Try disposing of all image data before loading new images.
The documentation says that having a UIImage doesn't necessarily imply that the image is actually stored in memory, because it could be purged from the image cache. But it does say that if you try to draw it, it will be pulled back into memory. Maybe it starts purging from its image cache before it warns you about the low memory condition. That explains everything you're seeing.

Difference between [UIImage imageNamed...] and [UIImage imageWithData...]?

I want to load some images into my application from the file system. There's 2 easy ways to do this:
[UIImage imageNamed:fullFileName]
or:
NSString *fileLocation = [[NSBundle mainBundle] pathForResource:fileName ofType:extension];
NSData *imageData = [NSData dataWithContentsOfFile:fileLocation];
[UIImage imageWithData:imageData];
I prefer the first one because it's a lot less code, but I have seen some people saying that the image is cached and that this method uses more memory? Since I don't trust people on most other forums, I thought I'd ask the question here, is there any practical difference, and if so which one is 'better'?
I have tried profiling my app using the Object Allocation instrument, and I can't see any practical difference, though I have only tried in the simulator, and not on an iPhone itself.
It depends on what you're doing with the image. The imageNamed: method does cache the image, but in many cases that's going to help with memory use. For example, if you load an image 10 times to display along with some text in a table view, UIImage will only keep a single representation of that image in memory instead of allocating 10 separate objects. On the other hand, if you have a very large image and you're not re-using it, you might want to load the image from a data object to make sure it's removed from memory when you're done.
If you don't have any huge images, I wouldn't worry about it. Unless you see a problem (and kudos for checking Object Allocation instead of preemptively optimizing), I would choose less lines of code over negligible memory improvements.
In my experience [UIImage imageNamed:] has dramatically better performance, especially when used in UITableViews.
It's not just the memory but also decoding the image. Having it cached is much faster.
As the API reference of UIImage says :
+(UIImage *)imageNamed:(NSString *)name
This 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.
+(UIImage *)imageWithContentsOfFile:(NSString *)path
This method does not cache the image object.
so,we can see that if you have a lot of same UI elements(such as UITableViewCell) that may use same image(often as an icons),and due to performance , of course we want to reuse the same image , so that we will save some memory for other use . Generrally the reused image is often used in the ui element that our user may operate on it lots of times . So it values for us to reuse it .So you can choose to use imageNamed method .
And on the other hand , in an application , there will be some UI element that will be there during the app's life cycle,such as a Button , a logo view , so these images used by these ui elements may also be there during the app's life cycle ,you wouldn't consider whether these image should be cache or not .So you can choose to use imageNamed method .
On the contrary,in an application , there are often some UI Elements that created dynamically. For example , our application support dynamic background , so that user can choose the background they like .And the background may be an image .So we may have a interface that list lots of different background (often show by use UIImageView) for user to choose ,we can name the list view MyBackgroundListView.So once the user chooses an background image , the MyBackgroundListView should be destroyed , because it has finishs its function .The next time the user want to change his/her background , we can create MyBackgroundListView again .So the images used by MyBackgroundListView shouldn't be cached , or our application's memory will run out .So this time you should use
imageWithContentsOfFile method.
As the Apple's doc Supporting High-Resolution Screens In Views says
On devices with high-resolution screens, the imageNamed:, imageWithContentsOfFile:, and initWithContentsOfFile: methods automatically looks for a version of the requested image with the #2x modifier in its name. If it finds one, it loads that image instead. If you do not provide a high-resolution version of a given image, the image object still loads a standard-resolution image (if one exists) and scales it during drawing.
so you would worry about the image's search path for retina screen problem . IOS will help you deal with it.
Sorry for my poor English . May it be helpful.
If you don't want your image do be cached you can also use initWithContentsOfFile directly :
NSString *fileLocation = [[NSBundle mainBundle] pathForResource:fileName ofType:extension];
UIImage* yourImage = [[[UIImage alloc] initWithContentsOfFile:imagePath] autorelease];
I've also been told that [UIImage imageNamed:] does a little bit too much caching, and images are not often released. I was told to be careful of using it.
imageWithData is useful when you store your image binary in a database or progressively downloading large image from the web.
I would not use imagenamed if your app has loads of big images which are not the same. I experienced app crashing due to using too much of it.
I don't believe that the image gets cached at all, and I don't know why you are all saying that. UIImage is a subclass of NSObject which uses reference counters to keep track of the things that it is related to. So when you load an image it does that same thing. If you load the same image multiple times it will(or should) have only one copy of the image in memory and just increment the reference counter every time you have to use something with that image. By Reference Counters I mean that when the count gets to 0 it deletes itself. so "alloc", "retain" are each +1 to the count and "release" is -1. Not only is it a better way to manage memory but this style of programming also helps clean up memory leaks.