Skip to content

Instantly share code, notes, and snippets.

@atljeremy
Last active January 2, 2016 09:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save atljeremy/8284796 to your computer and use it in GitHub Desktop.
Save atljeremy/8284796 to your computer and use it in GitHub Desktop.
DownloadImageOperation
@interface DownloadImageOperation() <NSURLConnectionDataDelegate, NSURLConnectionDelegate>
@property (nonatomic, strong) NSManagedObjectContext* innerMOC;
@property (nonatomic, strong, readwrite) PhotoID* photoID;
@property (nonatomic, strong) UIImage* downloadedImage;
@property (nonatomic, strong) NSURLConnection* connection;
@property (nonatomic, strong) NSMutableData* imageData;
@property (nonatomic, strong) NSDate* startedReceivingData;
@property (nonatomic, strong) NSDate* finishedReceivingData;
@property (nonatomic, strong) NSDictionary* responseHeaders;
@end
@implementation DownloadImageOperation
- (instancetype)initWithPhotoObjectID:(PhotoID*)photoID_
{
if (self = [super init]) {
_photoID = photoID_;
}
return self;
}
- (void)main
{
@autoreleasepool {
if (self.isCancelled) {
return;
}
self.innerMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
[self.innerMOC setParentContext:self.moc];
Photo* photo = [Photo photoForPhotoID:self.photoID forMOC:self.innerMOC];
NSURL* imageURL = [NSURL URLWithString:[kEnvironmentImageServer stringByAppendingString:photo.serverURL]];
NSURLRequest* request = [NSURLRequest requestWithURL:imageURL];
photo.startedConnection = [NSDate date];
self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
CFRunLoopRun();
/**
* NOTE: Execution continues on to this point without waiting for NSURLConnection considering NSURLConnection operates within it's own thread.
*/
if (self.responseHeaders) {
NSLog(@"Headers: %@", self.responseHeaders);
photo.responseHeaders = [NSString stringWithFormat:@"%@", self.responseHeaders];
int age = [[self.responseHeaders objectForKey:@"Age"] intValue];
if (age > 0) {
photo.cacheHit = @(YES);
}
}
photo.startedReceivingData = self.startedReceivingData;
photo.finishedReceivingData = self.finishedReceivingData;
photo.downloadTimeValue = photo.time;
photo.size = @([self.imageData length]);
if (self.isCancelled) {
self.imageData = nil;
self.downloadedImage = nil;
return;
}
if (self.imageData) {
self.downloadedImage = [UIImage imageWithData:self.imageData];
[photo setFileSystemURLWithImage:self.downloadedImage];
}
self.imageData = nil;
if (self.isCancelled) {
self.downloadedImage = nil;
return;
}
NSError* error;
if ([[self innerMOC] hasChanges] && ![[self innerMOC] save:&error]) {
NSLog(@"Failure: %@\n%@", [error localizedDescription], [error userInfo]);
abort();
}
[[self moc] performBlock:^{
NSError *error;
if ([[self moc] hasChanges] && ![[self moc] save:&error]) {
NSLog(@"Main MOC Failure: %@\n%@", [error localizedDescription], [error userInfo]);
}
}];
}
}
- (NSError*)error
{
NSError* error = nil;
if (!self.downloadedImage) {
NSDictionary* userInfo = @{NSLocalizedDescriptionKey: @"Unable to download resource"};
error = [NSError errorWithDomain:@"DownloadImageOperationErrorDomain" code:NSURLErrorResourceUnavailable userInfo:userInfo];
}
return error;
}
- (void)setSuccessCallbackQueue:(dispatch_queue_t)successCallbackQueue {
if (successCallbackQueue != _successCallbackQueue) {
if (_successCallbackQueue) {
_successCallbackQueue = NULL;
}
if (successCallbackQueue) {
_successCallbackQueue = successCallbackQueue;
}
}
}
- (void)setFailureCallbackQueue:(dispatch_queue_t)failureCallbackQueue {
if (failureCallbackQueue != _failureCallbackQueue) {
if (_failureCallbackQueue) {
_failureCallbackQueue = NULL;
}
if (failureCallbackQueue) {
_failureCallbackQueue = failureCallbackQueue;
}
}
}
- (void)setCompletionBlockWithSuccess:(void (^)(DownloadImageOperation *operation, UIImage* downloadedImage))success
failure:(void (^)(DownloadImageOperation *operation, NSError *error))failure
{
__weak typeof(self) weakSelf = self;
self.completionBlock = ^{
if (weakSelf.error) {
if (failure) {
dispatch_async(weakSelf.failureCallbackQueue ?: dispatch_get_main_queue(), ^{
failure(weakSelf, weakSelf.error);
});
}
} else {
if (success) {
dispatch_async(weakSelf.successCallbackQueue ?: dispatch_get_main_queue(), ^{
success(weakSelf, weakSelf.downloadedImage);
});
}
}
};
}
#pragma mark ----------------------
#pragma mark NSURLConnectionDelegate/DataDelegate
#pragma mark ----------------------
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if ([connection isEqual:self.connection]) {
self.finishedReceivingData = [NSDate date];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
dispatch_async(dispatch_get_main_queue(), ^{
// [self configureForNoPropertyPhoto];
});
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if ([connection isEqual:self.connection]) {
if (response) {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
self.responseHeaders = httpResponse.allHeaderFields;
}
[self.imageData setLength:0];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if ([connection isEqual:self.connection]) {
self.startedReceivingData = [NSDate date];
[self.imageData appendData:data];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment