From d53a47e982acbcfc2483bf2dcf8aa87517da7ea4 Mon Sep 17 00:00:00 2001 From: Charlie Savage Date: Fri, 26 Apr 2013 21:43:11 -0600 Subject: [PATCH] Remove async calls from SDWebImageDownloader. The operation is already run in a background thread also the async calls are unnecessary. --- SDWebImage/SDWebImageDownloader.m | 5 +- SDWebImage/SDWebImageDownloaderOperation.h | 1 - SDWebImage/SDWebImageDownloaderOperation.m | 214 ++++++++++----------- 3 files changed, 98 insertions(+), 122 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index af17cd23..932b3e0a 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -23,7 +23,6 @@ static NSString *const kCompletedCallbackKey = @"completed"; @property (strong, nonatomic) NSMutableDictionary *URLCallbacks; @property (strong, nonatomic) NSMutableDictionary *HTTPHeaders; // This queue is used to serialize the handling of the network responses of all the download operation in a single queue -@property (SDDispatchQueueSetterSementics, nonatomic) dispatch_queue_t workingQueue; @property (SDDispatchQueueSetterSementics, nonatomic) dispatch_queue_t barrierQueue; @end @@ -72,7 +71,6 @@ static NSString *const kCompletedCallbackKey = @"completed"; _downloadQueue.maxConcurrentOperationCount = 2; _URLCallbacks = NSMutableDictionary.new; _HTTPHeaders = [NSMutableDictionary dictionaryWithObject:@"image/*" forKey:@"Accept"]; - _workingQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloader", DISPATCH_QUEUE_SERIAL); _barrierQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderBarrierQueue", DISPATCH_QUEUE_CONCURRENT); } return self; @@ -81,7 +79,6 @@ static NSString *const kCompletedCallbackKey = @"completed"; - (void)dealloc { [self.downloadQueue cancelAllOperations]; - SDDispatchQueueRelease(_workingQueue); SDDispatchQueueRelease(_barrierQueue); } @@ -124,7 +121,7 @@ static NSString *const kCompletedCallbackKey = @"completed"; request.HTTPShouldHandleCookies = NO; request.HTTPShouldUsePipelining = YES; request.allHTTPHeaderFields = wself.HTTPHeaders; - operation = [SDWebImageDownloaderOperation.alloc initWithRequest:request queue:wself.workingQueue options:options progress:^(NSUInteger receivedSize, long long expectedSize) + operation = [SDWebImageDownloaderOperation.alloc initWithRequest:request options:options progress:^(NSUInteger receivedSize, long long expectedSize) { if (!wself) return; SDWebImageDownloader *sself = wself; diff --git a/SDWebImage/SDWebImageDownloaderOperation.h b/SDWebImage/SDWebImageDownloaderOperation.h index b7afd7f4..154a4e5a 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.h +++ b/SDWebImage/SDWebImageDownloaderOperation.h @@ -16,7 +16,6 @@ @property (assign, nonatomic, readonly) SDWebImageDownloaderOptions options; - (id)initWithRequest:(NSURLRequest *)request - queue:(dispatch_queue_t)queue options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index 651bc765..f8e72209 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -21,7 +21,6 @@ @property (assign, nonatomic) long long expectedSize; @property (strong, nonatomic) NSMutableData *imageData; @property (strong, nonatomic) NSURLConnection *connection; -@property (SDDispatchQueueSetterSementics, nonatomic) dispatch_queue_t queue; @end @@ -31,11 +30,10 @@ BOOL responseFromCached; } -- (id)initWithRequest:(NSURLRequest *)request queue:(dispatch_queue_t)queue options:(SDWebImageDownloaderOptions)options progress:(void (^)(NSUInteger, long long))progressBlock completed:(void (^)(UIImage *, NSData *, NSError *, BOOL))completedBlock cancelled:(void (^)())cancelBlock +- (id)initWithRequest:(NSURLRequest *)request options:(SDWebImageDownloaderOptions)options progress:(void (^)(NSUInteger, long long))progressBlock completed:(void (^)(UIImage *, NSData *, NSError *, BOOL))completedBlock cancelled:(void (^)())cancelBlock { if ((self = [super init])) { - _queue = queue; _request = request; _options = options; _progressBlock = [progressBlock copy]; @@ -51,42 +49,36 @@ - (void)start { - dispatch_async(dispatch_get_main_queue(), ^ + if (self.isCancelled) { - if (self.isCancelled) - { - self.finished = YES; - [self reset]; - return; - } + self.finished = YES; + [self reset]; + return; + } - self.executing = YES; - self.connection = [NSURLConnection.alloc initWithRequest:self.request delegate:self startImmediately:NO]; + self.executing = YES; + self.connection = [NSURLConnection.alloc initWithRequest:self.request delegate:self startImmediately:NO]; - // If not in low priority mode, ensure we aren't blocked by UI manipulations (default runloop mode for NSURLConnection is NSEventTrackingRunLoopMode) - if (!(self.options & SDWebImageDownloaderLowPriority)) - { - [self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; - } + [self.connection start]; - [self.connection start]; + if (self.connection) + { + if (self.progressBlock) + { + self.progressBlock(0, -1); + } + [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:self]; - if (self.connection) + // Make sure to run the runloop in our background thread so it can process downloaded data + CFRunLoopRun(); + } + else + { + if (self.completedBlock) { - if (self.progressBlock) - { - self.progressBlock(0, -1); - } - [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:self]; + self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"Connection can't be initialized"}], YES); } - else - { - if (self.completedBlock) - { - self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"Connection can't be initialized"}], YES); - } - } - }); + } } - (void)cancel @@ -118,14 +110,11 @@ - (void)reset { - dispatch_async(dispatch_get_main_queue(), ^ - { - self.cancelBlock = nil; - self.completedBlock = nil; - self.progressBlock = nil; - self.connection = nil; - self.imageData = nil; - }); + self.cancelBlock = nil; + self.completedBlock = nil; + self.progressBlock = nil; + self.connection = nil; + self.imageData = nil; } - (void)setFinished:(BOOL)finished @@ -183,89 +172,85 @@ if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0 && self.completedBlock) { - dispatch_async(self.queue, ^ + // The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/ + // Thanks to the author @Nyx0uf + + // Get the total bytes downloaded + const NSUInteger totalSize = self.imageData.length; + + // Update the data source, we must pass ALL the data, not just the new bytes + CGImageSourceRef imageSource = CGImageSourceCreateIncremental(NULL); + CGImageSourceUpdateData(imageSource, (__bridge CFDataRef)self.imageData, totalSize == self.expectedSize); + + if (width + height == 0) { - // The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/ - // Thanks to the author @Nyx0uf - - // Get the total bytes downloaded - const NSUInteger totalSize = self.imageData.length; - - // Update the data source, we must pass ALL the data, not just the new bytes - CGImageSourceRef imageSource = CGImageSourceCreateIncremental(NULL); - CGImageSourceUpdateData(imageSource, (__bridge CFDataRef)self.imageData, totalSize == self.expectedSize); - - if (width + height == 0) + CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL); + if (properties) { - CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL); - if (properties) - { - CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight); - if (val) CFNumberGetValue(val, kCFNumberLongType, &height); - val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); - if (val) CFNumberGetValue(val, kCFNumberLongType, &width); - CFRelease(properties); - } + CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight); + if (val) CFNumberGetValue(val, kCFNumberLongType, &height); + val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); + if (val) CFNumberGetValue(val, kCFNumberLongType, &width); + CFRelease(properties); } + } - if (width + height > 0 && totalSize < self.expectedSize) - { - // Create the image - CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL); + if (width + height > 0 && totalSize < self.expectedSize) + { + // Create the image + CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL); #ifdef TARGET_OS_IPHONE - // Workaround for iOS anamorphic image - if (partialImageRef) + // Workaround for iOS anamorphic image + if (partialImageRef) + { + const size_t partialHeight = CGImageGetHeight(partialImageRef); + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef bmContext = CGBitmapContextCreate(NULL, width, height, 8, width * 4, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst); + CGColorSpaceRelease(colorSpace); + if (bmContext) { - const size_t partialHeight = CGImageGetHeight(partialImageRef); - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGContextRef bmContext = CGBitmapContextCreate(NULL, width, height, 8, width * 4, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst); - CGColorSpaceRelease(colorSpace); - if (bmContext) - { - CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = width, .size.height = partialHeight}, partialImageRef); - CGImageRelease(partialImageRef); - partialImageRef = CGBitmapContextCreateImage(bmContext); - CGContextRelease(bmContext); - } - else - { - CGImageRelease(partialImageRef); - partialImageRef = nil; - } + CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = width, .size.height = partialHeight}, partialImageRef); + CGImageRelease(partialImageRef); + partialImageRef = CGBitmapContextCreateImage(bmContext); + CGContextRelease(bmContext); } + else + { + CGImageRelease(partialImageRef); + partialImageRef = nil; + } + } #endif - if (partialImageRef) + if (partialImageRef) + { + UIImage *image = [UIImage decodedImageWithImage:SDScaledImageForPath(self.request.URL.absoluteString, [UIImage imageWithCGImage:partialImageRef])]; + CGImageRelease(partialImageRef); + dispatch_async(dispatch_get_main_queue(), ^ { - UIImage *image = [UIImage decodedImageWithImage:SDScaledImageForPath(self.request.URL.absoluteString, [UIImage imageWithCGImage:partialImageRef])]; - CGImageRelease(partialImageRef); - dispatch_async(dispatch_get_main_queue(), ^ + if (self.completedBlock) { - if (self.completedBlock) - { - self.completedBlock(image, nil, nil, NO); - } - }); - } + self.completedBlock(image, nil, nil, NO); + } + }); } + } - CFRelease(imageSource); - }); + CFRelease(imageSource); NSUInteger received = self.imageData.length; - dispatch_async(dispatch_get_main_queue(), ^ + + if (self.progressBlock) { - if (self.progressBlock) - { - self.progressBlock(received, self.expectedSize); - } - }); + self.progressBlock(received, self.expectedSize); + } } } - (void)connectionDidFinishLoading:(NSURLConnection *)aConnection { + CFRunLoopStop(CFRunLoopGetCurrent()); self.connection = nil; [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil]; @@ -282,23 +267,17 @@ } else { - dispatch_async(self.queue, ^ + UIImage *image = [UIImage decodedImageWithImage:SDScaledImageForPath(self.request.URL.absoluteString, self.imageData)]; + if (CGSizeEqualToSize(image.size, CGSizeZero)) { - UIImage *image = [UIImage decodedImageWithImage:SDScaledImageForPath(self.request.URL.absoluteString, self.imageData)]; - dispatch_async(dispatch_get_main_queue(), ^ - { - if (CGSizeEqualToSize(image.size, CGSizeZero)) - { - completionBlock(nil, nil, [NSError errorWithDomain:@"SDWebImageErrorDomain" code:0 userInfo:@{NSLocalizedDescriptionKey: @"Downloaded image has 0 pixels"}], YES); - } - else - { - completionBlock(image, self.imageData, nil, YES); - } - self.completionBlock = nil; - [self done]; - }); - }); + completionBlock(nil, nil, [NSError errorWithDomain:@"SDWebImageErrorDomain" code:0 userInfo:@{NSLocalizedDescriptionKey: @"Downloaded image has 0 pixels"}], YES); + } + else + { + completionBlock(image, self.imageData, nil, YES); + } + self.completionBlock = nil; + [self done]; } } else @@ -309,6 +288,7 @@ - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { + CFRunLoopStop(CFRunLoopGetCurrent()); [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil]; if (self.completedBlock)