My application have UITableView. I am using custom cell that have lable and UIImage. Its working fine for normal scrolling. But if I scroll that for long time, then images get disappeared. And there was error = 24 (to many open files) in console.
From Google, I got that instead of using UIImage imageNamed, used initWithContentOfFile. But that dose not work. Please help.
Edit Adding code written in comments:
This is the code used for adding the image to the cell:
UIImage *img =[[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"sms_icon" ofType:#"png"]]; [cell.img setImage:img]; [img release];
The documentation says
The method (+ImageNamed:) 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.
On a device running iOS 4 or later, the behavior is identical if the device’s screen has a scale of 1.0. If the screen has a scale of 2.0, this method first searches for an image file with the same filename with an #2x suffix appended to it. For example, if the file’s name is button, it first searches for button#2x. If it finds a 2x, it loads that image and sets the scale property of the returned UIImage object to 2.0. Otherwise, it loads the unmodified filename and sets the scale property to 1.0.
On iOS 4 and later, if the file is in PNG format, it is not necessary to specify the .PNG filename extension. Prior to iOS 4, you must specify the filename extension.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.
When I try to fetch the images in UITableView using NSURLUIImage image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://mysite.com/mobile/abc.jpg]]];
my application get freezes until the images loaded. Also when I scroll the table it get images from the server again and scroll get stuck for some time.
I know this is happening because of downloading images synchronously from server.
Is there any solution so that I can download the image asynchronously from server and store it locally or in cache so that when table scrolls it did not get images again from server.
Thanks
Check out EGOImageLoading by enormego. Works just like UIImage (and caches images) but lets you load from HTTP asynchronously.
You can create your own class which leverages NSURLConnection and it's various Asynchronous methods to load your images in the background and then have a callback to display it in the cell.
However, there are some excellent libraries which do exactly what you've described. HJCache is one i've used and recommend for this sole purpose
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.
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.
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.