Skip to content

Instantly share code, notes, and snippets.

@algal
Created May 22, 2014 17:08
Show Gist options
  • Save algal/14849df897885c79952e to your computer and use it in GitHub Desktop.
Save algal/14849df897885c79952e to your computer and use it in GitHub Desktop.
Simple asynchronous UIImageView image-loading using only built-in framework components
//
// UIImageView+ALGDataTask.h
// VideoClient
//
// Created by Alexis Gallagher on 2014-01-18.
// Copyright (c) 2014 Bloom Filter. All rights reserved.
//
#import <UIKit/UIKit.h>
/**
This is a lightweight category for adding asynchronous image loading to UIImageView. If you
need something maximally configurable, full-featured, and compatible with old versions of iOS,
you want AFNetworking's UIImageView category. If you want something you can fully comprehend in
five minutes, this is it.
The approach is just to use framework components as much as possibe.
Instead of using NSOperationQueue to queue requests, use iOS7's NSURLSession. It will
enqueue requests, restrict simultaneous connections, and allow group cancellation.
Instead of creating a UIImage cache, set the NSURLCachePolicy on that session. This cache will
spare you from repeated retrieval of the same data, which is the main thing to avoid. (However, I
do not believe it will save you from the performance cost of repeated image decoding.)
*/
@interface UIImageView (ALGDataTask)
/**
Asynchronously load an image from imageURL using session, canceling any previous request.
@param imageURL The URL of the image.
@param scale the scale factor applied to the image.
@param session the NSURLSession to use for the request
@discussion
If you want caching of loaded images, then configure the URLCache and requestCachePolicy of your NSURLSession.
For instance, to cache data aggressively (igorning expiration headers) you could do
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.requestCachePolicy = NSURLRequestReturnCacheDataElseLoad;
NSURLSession * session = [NSURLSession sessionWithConfiguration:config];
Or to use a dedicated cache (separate from the shared default cache), you could do
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.URLCache = [[NSURLCache alloc] initWithMemoryCapacity:1000000
diskCapacity:2000000
diskPath:@"headshotCache"];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config];
If you want a placeholder image before loading completes, then just set that as the image before starting loading. For instance, you could do
imageView.image = [UIImage imageNamed:@"myplaceholder"];
[imageView setImageWithURL:myURL usingSession:session];
*/
-(void)setImageWithURL:(NSURL*)imageURL scale:(CGFloat)scale usingSession:(NSURLSession*)session;
@end
//
// UIImageView+ALGDataTask.m
// VideoClient
//
// Created by Alexis Gallagher on 2014-01-18.
// Copyright (c) 2014 Bloom Filter. All rights reserved.
//
#import "UIImageView+ALGDataTask.h"
#import <objc/runtime.h>
static char kALGSessionDataTaskKey;
@implementation UIImageView (ALGDataTask)
-(void)setDataTask:(NSURLSessionDataTask*)dataTask
{
objc_setAssociatedObject(self, &kALGSessionDataTaskKey, dataTask, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSURLSessionDataTask*)dataTask
{
return (NSURLSessionDataTask *)objc_getAssociatedObject(self, &kALGSessionDataTaskKey);
}
-(void)setImageWithURL:(NSURL*)imageURL scale:(CGFloat)scale usingSession:(NSURLSession*)session
{
if (self.dataTask) {
[self.dataTask cancel];
}
if (imageURL) {
__weak typeof(self) weakSelf = self;
self.dataTask = [session dataTaskWithURL:imageURL
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
__strong __typeof(weakSelf) strongSelf = weakSelf;
if (error) {
NSLog(@"ERROR: %@", error);
}
else {
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
if (200 == httpResponse.statusCode) {
UIImage * image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
strongSelf.image = image;
});
} else {
NSLog(@"Couldn't load image at URL: %@", imageURL);
NSLog(@"HTTP %ld", (long)httpResponse.statusCode);
}
}
}];
[self.dataTask resume];
}
return;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment