Last active
January 2, 2016 09:39
-
-
Save atljeremy/8284796 to your computer and use it in GitHub Desktop.
DownloadImageOperation
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
@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