views:

375

answers:

3

Hey guys,

I have a UIImage that I'm instantiating using imageWithData: (the data is loaded from the bundle using [NSData dataWithContentsOfFile:]).

I'm then drawing the image like so:

NSData *imageData =  [NSData dataWithContentsOfFile:fileLocation];
UIImage *myImage = [UIImage imageWithData:imageData];

//These lines are superfluous from what I can tell, replacing with
//UIImage *myImage = [UIImage imagedNamed:imageName]; very soon.

[myImage drawAtPoint:CGPointMake(0,0)];
//myImage will be released at the end of the run loop

My question is this: The UIImage created is autoreleased. What happens in terms of memory when the UIImage is drawn to the view and then the UIImage is deallocated out of existence. Obviously, visually, the image is still there as it has been drawn to a context.

Does the memory usage double if the UIImage is valid AND has been drawn to the view, and then return to the same amount as if only one UIImage existed after the UIImage has been deallocated?


Now going down another route.

If I used [UIImage imageNamed:] to instantiate the image, then the UIImage class has its own image cache of sorts and will only ever hold one true instance of a particular image (regardless of how many UIImage instances are created to represent that one image).

My other question is: What happens to the image in the cache if I draw it to a context and then the UIimage is released (via autorelease at the end of the run loop)? Does the image stay in the cache an consume memory? Is it removed because no other UIImage instances are using it?

Any help would be great, thanks!

+1  A: 

At any point, when you "draw to context", the context does not hold a reference to the image. Instead, drawing will place the actual bits of pixels on the context, so it doesn't need the reference to UIImage (or anything drawn to it - NSString, NSPath etc).

Regarding imageNamed:, it will never be really released - what you get is a refernece that you don't (and shouldn't) release, but the cached image might still be there.

Aviad Ben Dov
I won't be releasing it myself. [UIImage imageNamed:] returns an autoreleased UIImage instance. It'll release itself at the end of the run loop. What I want to know is if the cached image will be freed upon deallocation of any UIImages that reference it?
Jasarien
The spec doesn't say if it releases the cached images or not. I would assume it doesn't. It might do so in the system-equivalent of `didReceiveMemoryWarning`, but again: not specified to my knowledge.
Aviad Ben Dov
imageNamed: images are cached until the system-equivalent of didReceiveMemoryWarning, but only on 3.0--on 2.x, a bug existed where the cache would never be flushed.
rpetrich
That's very interesting, thanks rpetrich.
Jasarien
A: 

It really depends on where you're creating the UIImage instance itself. If this is a UIView subclass, are you creating the UIImage in -drawRect: or -initWithFrame: or somewhere else? If you load the image once (in your init or with a setter which retains, etc.) then there shouldn't be a problem. However if you're creating the image over and over again in -drawRect: then at the very least you will have a performance problem.

jbrennan
The main issue I have here, is that I don't want to keep hold of an image I won't be using until drawRect.The view doesn't redraw itself very often, so I don't think its that much of a problem to instantiate the image within drawRect.If I instantiate it in init, then the image is consuming memory even thought its not being used - which doesn't make sense to me.
Jasarien
Then I would go with `[UIImage imageNamed:]` because as you said, it caches the image, but might flush the cache if memory gets tight. This way you've still got your reference, but the actual data itself might get flushed. UIImage takes care of all the hard work.
jbrennan
+1  A: 

I really recommend starting with simple code here and then optimizing where you are actually having trouble. The kind of space optimizations you're describing are likely to create serious time problems (recreating the UIImage in -drawRect: for instance is very expensive). That said, let's look through the various questions:

  • First, as I said, be careful with doing expensive work in -drawRect:. You have little control over how often or when it gets called, and any expensive work here (like creating a new UIImage, particularly if you have to read it from disk) can seriously impact UI performance.

  • I'm assuming that there's a lot more to your -drawRect: then this, correct? UIImageView is optimized for what you've done here, both in speed and in memory. But if your view is much more complicated, then drawing the image yourself is better than creating lots of sub-views.

  • As has been noted, when you call -drawAtPoint:, the copy you make is a bitmap representation (blended with any other drawing that is done). It's unrelated to the original UIImage in terms of memory usage. You cannot trade one for the other. The memory required for the bitmap representation is a function of the view size and bit depth, and you're not going to be able to change it. It doesn't care if the UIImage exists after it's been drawn.

  • -imageNamed: does do caching for you and is generally a good choice. Note that it doesn't clear its cache in low-memory situations. The UIImages themselves transparently dump their underlying data if they were loaded from a file (and they dump extra representations in any case). The UIImage reference includes information about how this is done.

  • If you're very concerned about performance around these images (space or time), and you don't need the functionality of UIImage, you should be working with CGImages. They are not as flexible as UIImages, and they're more complex to code, but they are more efficient. That said, UIImages are good for most purposes.

Rob Napier
UIImageView isn't optimized, it's just there as a convenience. Same thing goes for UILabel.
rpetrich
It claims it is (see the Subclassing Notes). It bypasses drawRect:. Haven't dug into what it does instead, but they claim to be doing something fancy.
Rob Napier