TestsTested | ✓ |
LangLanguage | Obj-CObjective C |
License | MIT |
ReleasedLast Release | Dec 2014 |
Maintained by Mark Smith.
On iOS, the UIImage method imageNamed:
optimizes image loading in two ways:
The first optimization saves (loading) time at the cost of (memory) space.
For images that currently exist as UIImage objects in the running application, the second optimization saves both time and space; there's no need to load or decode the image, and there aren't duplicate copies each occupying memory.
CZSharedImage is a tiny library that provides the second optimization for images loaded using UIImage#imageWithContentsOfFile:
and UIImage#imageWithData:
.
Note that CZSharedImage is not a cache; it simply tracks live UIImage objects. Its value is in cases where an image is used multiple times in a view (accessory images in a table view, for instance), or multiple times in a navigation hierarchy.
CZSharedImage requires ARC and iOS 6.0. (It uses the NSMapTable class introduced in 6.0.)
Import the header file CZSharedImage.h.
For usage examples, see CZSharedImageTests.m or the example app.
In the example app, 100 instances of a 500x500 image (each occupying approximately 1MB of memory when decoded) are displayed on the screen. The resident size of the app when using UIImage#imageWithContentsOfFile:
is 99MB more than when using CZSharedImage#imageWithContentsOfFile:
.
Shared images are created using the CZSharedImage class.
+ (UIImage *)imageWithContentsOfFile:(NSString *)path;
+ (UIImage *)imageWithData:(NSData *)data;
+ (UIImage *)imageWithData:(NSData *)data scale:(CGFloat)scale;
Simply replace calls to the above three UIImage methods with the CZSharedImage methods of the same name. If the associated UIImage object already exists in the running app, the method will immediately return a reference to that object. If not, it will be loaded as usual by the corresponding UIImage initializer.
UIImage *image = [CZSharedImage imageWithContentsOfFile:@"/path/to/image/file"];
Note that in the case of images loaded using imageWithData:
, subsequent requests are matched using an MD5 hash of the data. A more efficient mechanism is to manually associate the image with a chosen path; see the next section for details.
+ (UIImage *)imageForPath:(NSString *)path;
+ (void)setImage:(UIImage *)image forPath:(NSString *)path;
For cases where an image is loaded using some mechanism other than the three imageWith... methods (for instance, over the network), it can still be manually associated with a path such as the URL for subsequent requests:
// Try to get a reference to this image.
NSString *path = @"http://example.com/foo.png";
UIImage *image = [CZSharedImage imageForPath:path];
// If not available, fetch the image and associate it with the URL.
// (Error handling not shown.)
if (!image) {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:path]];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
// While the fetched UIImage object below remains alive,
// CZSharedImage#imageForPath: will return a reference to it.
UIImage *image = [UIImage imageWithData:data];
[CZSharedImage setImage:image forPath:path];
...
}];
}
...
Similarly, an image fetched from a database could be associated with a unique path corresponding to the database row (and column if necessary):
// Try to get a reference to this image.
int personid = <...get row ID...>;
NSString *path = [NSString stringWithFormat:@"db:/person/%d", personid];
UIImage *image = [CZSharedImage imageForPath:path];
// If not available, fetch the image and associate it with the path.
// (Error handling not shown.)
if (!image) {
NSData *data = <...load image data...>;
// While the fetched UIImage object below remains alive,
// CZSharedImage#imageForPath: will return a reference to it.
UIImage *image = [CZSharedImage imageWithData:data];
[CZSharedImage setImage:image forPath:path];
}
...