65

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.

Matthias Bauch
  • 89,811
  • 20
  • 225
  • 247
rustyshelf
  • 44,963
  • 37
  • 98
  • 104
  • 2
    Alternatively, you could use [UIImage imageWithContentsOfFile:path], which does not cache the image. – bentford Jul 27 '10 at 18:14

8 Answers8

91

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.

Marc Charbonneau
  • 40,399
  • 3
  • 75
  • 82
10

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.

monjer
  • 2,809
  • 2
  • 21
  • 31
10

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.

Girish
  • 4,692
  • 4
  • 35
  • 55
Hunter
  • 4,343
  • 5
  • 42
  • 44
7

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];
CedricSoubrie
  • 6,657
  • 2
  • 39
  • 44
5

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.

Ben Gottlieb
  • 85,404
  • 22
  • 176
  • 172
  • I got in trouble with the caching. My app was loading images, then over-writing the image file, and that ended up causing really oddly messed up images and scary debug messages from the JPEG library. – Chris Lundie Nov 25 '08 at 03:54
  • 6
    I think this is out of date now. – Rog Aug 02 '11 at 13:34
3

imageWithData is useful when you store your image binary in a database or progressively downloading large image from the web.

Dan
  • 1,711
  • 1
  • 22
  • 36
0

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.

user281300
  • 1,427
  • 2
  • 19
  • 31
  • ditto , my app was crashing because of imageNamed on some larger images. I thought it was a memory leak, but there was no evidence of that at all. Took a while to realize because it was happening intermittently, but imageWithData ened up solving the problem. – yeahdixon Nov 30 '10 at 19:25
  • Roger: You got a link with info, to back that up? I got similar problems with imageNamed on and off (mostly with many and big images) and always used other initializers to get around the problem. – Jonny Oct 04 '11 at 13:12
-11

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.

andrew
  • 1
  • 1
    Could you please point us to any documentation that backs this? – Plumenator Dec 17 '10 at 10:41
  • 2
    Sorry - but I think *it is cached* and it's rather well known. For a good blog post (not my blogg thou) read here: http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/ – Magnus Jan 07 '11 at 08:01
  • Here is one source I found, scroll down to memory management sections. – andrew Feb 06 '11 at 00:06
  • Here is one source I found, scroll down to memory management sections. [link]http://cocoadevcentral.com/d/learn_objectivec/ Here is another, stack overflow with positive support. [link]http://stackoverflow.com/questions/6578/understanding-reference-counting-with-cocoa-objective-c – andrew Feb 06 '11 at 00:13
  • The links here are way out of date. See this related SO question: http://stackoverflow.com/questions/924740/dispelling-the-uiimage-imagenamed-fud – Rog Aug 02 '11 at 13:33
  • The caching has nothing to do with memory management or reference counting. It is the specific implementation of `UIImage imageNamed:` which internally uses a cache to improve the performance of retrieving the same image multiple times. Incidentally it does this by sharing the same instance of the loaded image data and incrementing its reference count, but only because it has a cache to look up previous instances. The behavior is not inherited from `NSObject`. – devios1 Jan 19 '15 at 20:00