Merge pull request #373 from cfis/download_cleanup
More SDWebImageDownloader Cleanup
This commit is contained in:
commit
4965c7d09f
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue