In case you ever need to enhance UIImageView to load it’s image lazily… like if it’s coming from a web URL.
I used this on my NSAttributedStrings+HTML open source project to improve performance and also be able to have images that are not available locally. But you don’t want to do a synchronous call over the web, that would block your UI.
I admit, it’s a quickie, but hey, sometimes those are also fun!
DTLazyImageView.h
@interface DTLazyImageView : UIImageView { NSURL *_url; BOOL _loading; } @property (nonatomic, retain) NSURL *url; @end |
DTLazyImageView.m
#import "DTLazyImageView.h" @implementation DTLazyImageView - (void)dealloc { self.image = nil; [_url release]; [super dealloc]; } - (void)loadImageAtURL:(NSURL *)url { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSData *data = [[NSData alloc] initWithContentsOfURL:url]; if (data) { UIImage *image = [[UIImage alloc] initWithData:data]; [self performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES]; [image release]; } [data release]; _loading = NO; [pool release]; } - (void)didMoveToSuperview { if (!self.image && _url && !_loading) { _loading = YES; [self performSelectorInBackground:@selector(loadImageAtURL:) withObject:_url]; } } #pragma mark Properties @synthesize url = _url; @end |
You can see, it’s very simple. When the view is added to a super view by means of addSubview then it starts loading the image on a background thread. Setting the image has to occur on the main thread because UIKit is not threadsafe, or at least has not been until recently.
Categories: Recipes
This is simple and clean, which is great. But be aware of one key drawback: you can’t cancel the loading of this image, since it is impossible to safely “kill” background threads. If the server takes a long time to respond, the background thread will continue running until it times out.
So I wouldn’t advise using this for situations like loading images in table view cells while scrolling, or else you’ll end up with lots of accumulated background threads waiting to finish.
Instead, consider using an asynchronous, cancellable NSURLConnection to load your image.
Thanks for the suggestion, just implemented that: http://www.cocoanetics.com/2011/05/and-now-lazy-loading-with-nsurlconnection/
Thanks for your post. I just wrote a Swift lazy loading UIImage view of it: http://initwith.tumblr.com/post/101865379170/swift-a-quick-lazy-loading-uiimageview