Best performance when using a stretchable UIImage - iphone

I need to use a stretchable UIImage hundreds of times in my app in multiple UIImageViews. Is it okay to globally reuse the same stretchable UIImage instead of having to recreate them in memory each time I need to add it to a UIImageView?
I know [UIImage imageNamed:] caches images for better performance, but this cannot be used for stretchable images!
Thanks,
Mike

Oh, absolutely, you should always store your image once and then call that same image every time you want to draw it. Typically for projects with a lot of images I have a single SpriteManager class that contains an NSDictionary full of sprites. Then I can reference each one via filename. This way each image is loaded only once, which is significantly faster.
The absolutely most efficient way to do this, though, is just to use OpenGL ES. And if you've got hundreds of images being drawn, I absolutely recommend that you do so.

Definitely: Reuse your image. Are you storing it in a global variable? Make sure you retain the image (or put it in a retained property fo some global class like your Application) since it probably came AutoReleased.

Related

Cutting down UIImage memory usage

I'm trying to find ways to cut down memory usage for my app right now, and I have an idea regarding UIImages. I make pretty extensive usage of UIImages, some of them common to multiple views. Is it a lot more memory efficient to instantiate a single UIImage and then use a pointer to that same image throughout the app rather than allocating a new UIImage for the same image in each view? Or, is the OS smart enough to sort of automatically cache a UIImage so that it is only stored in memory once? (doubt that's the case but I have to ask)
Thanks.
Straight from UIImage apple reference docs for imageNamed:
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.
You use a lot of images, so remember that [UIImage imageNamed:#""]; caches the images, so if you are having low memory problem use instead [UIImage imageWithContentsOfFile:#""]; that doesn't cache it. Maybe that can help you cut down memory usage.
When a view unloads set the GUI properties to nil in the viewDidUnload method of UIViewController subclasses.
Yes, it is more efficient to store a single UIImage and use pointers to it.
It is unlikely that the OS caches images in this way, and even if it did, using pointers gives you more fine control of when the image is released / deallocated so that you don't have to hope the OS is going to take care of it.

Is it possible to know if an image is in the iPhone system cache?

I am trying to improve scrolling performance of a UITableView. I am loading the images using imageNamed: and dispatch_async, but scrolling is very good once the images have been loaded into the cells. I would like to fade in the images only if they are not in the system cache to reduce the jarring effect of the images "popping" into view.
Is there a way to know if an image is already in the system cache?
There is no documented way to look inside the UIImage to check such things.
I think the only way to know for sure that the image is available immediately, is to force the UIImage to be loaded. This can be done in the background, by creating the UIImage and accessing it's pixels, using CGImage functions. If you ensure that there is no rescaling needed (i.e. don't put a 3000x2000 image in a 30x20 space) then it should display without a glitch.

Using system cache of UIImage objects with images loaded from disk cache (NSCachesDirectory)?

I'm trying to improve scrolling performance on a UITableView that uses cells with images fetched from the web, but stored in the NSCachesDirectory. The cells have a custom content view to draw the contents (an image).
When I use a placeholder image from the app bundle, using [UIImage imageNamed:#"Placeholder.png"], scrolling performance is super fast.
When I load an image from the disk cache (NSCachesDirectory) using [UIImage imageWithContentsOfFile:cachePath], scrolling performance gets worse.
According to the documentation, imageNamed: caches the image and imageWithContentsOfFile: does not.
How to use UIImage's system cache when using imageWithContentsOfFile: ?
Thanks a bunch!
It seems to be possible to use the path to an image in the NSCachesDirectory as argument for the [UIImage imageNamed:] method. The method accepts relative paths (relative to the app bundle), e.g.: #"../Library/Caches/SomeCachedImage.png" works.
UIImage automatically caches the image in memory if it is used multiple times, which improves the performance when an image is used multiple times in a table view.
The problem is most likely that you are loading and decompressing the image in the main run loop. This will block the user interface for a short time. You get much better performance if you do the loading and decompression in a seperate thread and only set the image in the main loop. (Which is also required for user interface changes, which setting an image on a UIImageView is)
This will require some more infrastructure. Like for example a notification scheme or key value observing.
You can't. imageWithContentsOfFile: will always load the image from file (though lazily). What you can do is create an in memory cache of you own with NSArrays or NSDictionaries, depending on how you'll want to do the lookup.

UIImageView and UIImage: How can I tweak the most performance out of them?

First: I've implement a fairly complex scrolling mechanism for images, that allows to scroll over a few hundred thousands (theoretically) in one single scroll view. This is done by preloading small portions upon scrolling, while re-using all UIImageViews. Currently all I do is to assign new created UIImage objects to those re-used UIImageViews.
It might be better if it's possible to also re-use those UIImage objects by passing new image data to them.
Now the problem is, that I am currently using the -imageNamed: method. The documentation says, that it caches the image.
Problems I see in this case with -imageNamed:
As the image gets scrolled out of the preloading range, it's not needed anymore. It would be bad if it tries to cache thousands of images while the user scrolls and scrolls and scrolls.
And if I would find a way to stuff new image data into the UIImage object for re-using it, then what happens with the old image that was cached?
So there is one method left, that seems interesting:
-initWithContentsOfFile:
This does not cache the image. And it doesn't use -autorelease, which is good in this case.
Do you think that in this case it would be better to use -initWithContentsOfFile:?
Only a benchmark can tell you for sure. I'm inclined to think that UIImage image caching is probably extremely efficient, given that it's used virtually everywhere in the OS. That said with the number of images you're displaying, your approach might help.
I'd say YES. You have too much images to keep all of them in cache so you can't use -imageNamed:. If your images are not displayed many times, you will not get lower performance.
I found one link regarding this which comments of imageNamed method http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/

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.