Serialize all background operations
This commit is contained in:
parent
326890b476
commit
651d8ff583
|
@ -19,6 +19,7 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
|
|||
|
||||
@property (strong, nonatomic) NSCache *memCache;
|
||||
@property (strong, nonatomic) NSString *diskCachePath;
|
||||
@property (assign, nonatomic) dispatch_queue_t ioQueue;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -44,6 +45,9 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
|
|||
{
|
||||
NSString *fullNamespace = [@"com.hackemist.SDWebImageCache." stringByAppendingString:ns];
|
||||
|
||||
// Create IO serial queue
|
||||
_ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL);
|
||||
|
||||
// Init default values
|
||||
_maxCacheAge = kDefaultCacheMaxCacheAge;
|
||||
|
||||
|
@ -87,6 +91,7 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
|
|||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
dispatch_release(_ioQueue);
|
||||
}
|
||||
|
||||
#pragma mark SDImageCache (private)
|
||||
|
@ -115,7 +120,7 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
|
|||
|
||||
if (toDisk)
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
|
||||
dispatch_async(self.ioQueue, ^
|
||||
{
|
||||
NSData *data = imageData;
|
||||
|
||||
|
@ -175,23 +180,9 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
|
|||
return;
|
||||
}
|
||||
|
||||
NSString *path = [self cachePathForKey:key];
|
||||
dispatch_io_t ioChannel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path.UTF8String, O_RDONLY, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), nil);
|
||||
dispatch_io_read(ioChannel, 0, SIZE_MAX, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(bool done, dispatch_data_t dispatchedData, int error)
|
||||
dispatch_async(self.ioQueue, ^
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
if (error != 2)
|
||||
{
|
||||
NSLog(@"SDWebImageCache: Error reading image from disk cache: errno=%d", error);
|
||||
}
|
||||
doneBlock(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_data_apply(dispatchedData, (dispatch_data_applier_t)^(dispatch_data_t region, size_t offset, const void *buffer, size_t size)
|
||||
{
|
||||
UIImage *diskImage = [UIImage decodedImageWithImage:SDScaledImageForPath(key, [NSData dataWithBytes:buffer length:size])];
|
||||
UIImage *diskImage = [UIImage decodedImageWithImage:SDScaledImageForPath(key, [NSData dataWithContentsOfFile:[self cachePathForKey:key]])];
|
||||
|
||||
if (diskImage)
|
||||
{
|
||||
|
@ -200,12 +191,7 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
|
|||
|
||||
doneBlock(diskImage);
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
dispatch_release(ioChannel);
|
||||
|
||||
}
|
||||
|
||||
- (void)removeImageForKey:(NSString *)key
|
||||
|
@ -224,7 +210,7 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
|
|||
|
||||
if (fromDisk)
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
|
||||
dispatch_async(self.ioQueue, ^
|
||||
{
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[self cachePathForKey:key] error:nil];
|
||||
});
|
||||
|
@ -238,7 +224,7 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
|
|||
|
||||
- (void)clearDisk
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
|
||||
dispatch_async(self.ioQueue, ^
|
||||
{
|
||||
[[NSFileManager defaultManager] removeItemAtPath:self.diskCachePath error:nil];
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:self.diskCachePath
|
||||
|
@ -250,7 +236,7 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
|
|||
|
||||
- (void)cleanDisk
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
|
||||
dispatch_async(self.ioQueue, ^
|
||||
{
|
||||
NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.maxCacheAge];
|
||||
NSDirectoryEnumerator *fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:self.diskCachePath];
|
||||
|
|
|
@ -20,6 +20,8 @@ NSString *const kCompletedCallbackKey = @"completed";
|
|||
|
||||
@property (strong, nonatomic) NSOperationQueue *downloadQueue;
|
||||
@property (strong, nonatomic) NSMutableDictionary *URLCallbacks;
|
||||
// This queue is used to serialize the handling of the network responses of all the download operation in a single queue
|
||||
@property (assign, nonatomic) dispatch_queue_t workingQueue;
|
||||
@property (assign, nonatomic) dispatch_queue_t barrierQueue;
|
||||
|
||||
@end
|
||||
|
@ -66,11 +68,19 @@ NSString *const kCompletedCallbackKey = @"completed";
|
|||
_downloadQueue = NSOperationQueue.new;
|
||||
_downloadQueue.maxConcurrentOperationCount = 10;
|
||||
_URLCallbacks = NSMutableDictionary.new;
|
||||
_workingQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloader", DISPATCH_QUEUE_SERIAL);
|
||||
_barrierQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderBarrierQueue", DISPATCH_QUEUE_CONCURRENT);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self.downloadQueue cancelAllOperations];
|
||||
dispatch_release(_workingQueue);
|
||||
dispatch_release(_barrierQueue);
|
||||
}
|
||||
|
||||
- (void)setMaxConcurrentDownloads:(NSInteger)maxConcurrentDownloads
|
||||
{
|
||||
_downloadQueue.maxConcurrentOperationCount = maxConcurrentDownloads;
|
||||
|
@ -93,7 +103,7 @@ NSString *const kCompletedCallbackKey = @"completed";
|
|||
request.HTTPShouldHandleCookies = NO;
|
||||
request.HTTPShouldUsePipelining = YES;
|
||||
[request addValue:@"image/*" forHTTPHeaderField:@"Accept"];
|
||||
operation = [SDWebImageDownloaderOperation.alloc initWithRequest:request options:options progress:^(NSUInteger receivedSize, long long expectedSize)
|
||||
operation = [SDWebImageDownloaderOperation.alloc initWithRequest:request queue:self.workingQueue options:options progress:^(NSUInteger receivedSize, long long expectedSize)
|
||||
{
|
||||
if (!wself) return;
|
||||
SDWebImageDownloader *sself = wself;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
@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,6 +21,7 @@
|
|||
@property (assign, nonatomic) long long expectedSize;
|
||||
@property (strong, nonatomic) NSMutableData *imageData;
|
||||
@property (strong, nonatomic) NSURLConnection *connection;
|
||||
@property (assign, nonatomic) dispatch_queue_t queue;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -29,10 +30,11 @@
|
|||
size_t width, height;
|
||||
}
|
||||
|
||||
- (id)initWithRequest:(NSURLRequest *)request options:(SDWebImageDownloaderOptions)options progress:(void (^)(NSUInteger, long long))progressBlock completed:(void (^)(UIImage *, NSError *, BOOL))completedBlock cancelled:(void (^)())cancelBlock
|
||||
- (id)initWithRequest:(NSURLRequest *)request queue:(dispatch_queue_t)queue options:(SDWebImageDownloaderOptions)options progress:(void (^)(NSUInteger, long long))progressBlock completed:(void (^)(UIImage *, NSError *, BOOL))completedBlock cancelled:(void (^)())cancelBlock
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_queue = queue;
|
||||
_request = request;
|
||||
_options = options;
|
||||
_progressBlock = progressBlock;
|
||||
|
@ -141,9 +143,12 @@
|
|||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
|
||||
{
|
||||
if (![response respondsToSelector:@selector(statusCode)] || [((NSHTTPURLResponse *)response) statusCode] < 400)
|
||||
{
|
||||
dispatch_async(self.queue, ^
|
||||
{
|
||||
self.expectedSize = response.expectedContentLength > 0 ? (NSUInteger)response.expectedContentLength : 0;
|
||||
self.imageData = [NSMutableData.alloc initWithCapacity:self.expectedSize];
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -162,7 +167,7 @@
|
|||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
|
||||
dispatch_async(self.queue, ^
|
||||
{
|
||||
[self.imageData appendData:data];
|
||||
|
||||
|
@ -236,7 +241,7 @@
|
|||
{
|
||||
self.connection = nil;
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
|
||||
dispatch_async(self.queue, ^
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil];
|
||||
|
||||
|
|
Loading…
Reference in New Issue