We all know about the mysterious hidden caching mechanism of the UIImage imageNamed: method. The Apple UIImage Class Reference it says:
In low memory situations, image data can be cleared from the UIImage object to free up memory in the system. This cleanup behavior only affects the image data stored inside the UIImage, and not the object itself. When you try to draw an image whose data has been cleared, the image object automatically reloads the data from its source file. However, this additional download step may result in a small performance penalty.
In fact, the image data will not be "cleared of the UIImage object to free up memory in the system," as the documentation shows. Instead, the application receives warnings about memory until it stops "due to memory pressure."
EDIT: When using regular links to image files in your Xcode project, UIImage caching works fine. This is easy when you go to directories of assets that are not issued in memory.
I have implemented a UIScrollView with several UIImageViews to scroll through a long list of images. When scrolling, the following images are loaded and assigned to the UIImageView image property, removing the strong link to the previously saved UIImage.
Due to the caching mechanism of imageNamed: I quickly run out of memory, and the application terminates with 170 MB of dedicated memory.
Of course, there are many interesting solutions for implementing custom caching mechanisms, including overriding the method of the imageNamed: class in a category. Often, the imageWithContentOfFile: class method is used instead, which does not imageWithContentOfFile: image data, as suggested by Apple developers at WWDC 2011.
These solutions are great for regular image files, although you need to get a path and file extension that is not as elegant as I would like.
I use the new Asset Catalogs introduced in Xcode 5, however, to use conditional image loading mechanisms depending on the device and efficient storage of image files. At the moment, there seems to be no direct way to load an image from an asset catalog without using imageNamed: unless I see an obvious solution.
Did you guys figure out the UIImage caching mechanism with resource directories?
I would like to implement a category in UIImage similar to the following:
static NSCache *_cache = nil; @implementation UIImage (Caching) + (UIImage *)cachedImageNamed:(NSString *)name { if (!_cache) _cache = [[NSCache alloc] init]; if (![_cache objectForKey:name]) { UIImage *image = ???;
Even better would be to gain more control over the internal UIImage cache and the ability to clear image data in low memory conditions, as described in the documentation when using Asset Directories.
Thanks for reading, and I look forward to your ideas!