Created
May 22, 2014 17:08
-
-
Save algal/14849df897885c79952e to your computer and use it in GitHub Desktop.
Simple asynchronous UIImageView image-loading using only built-in framework components
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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