Merge pull request #676 from matej/cache-gcd-fixes

Various GCD related fixes for SDImageCache
This commit is contained in:
Olivier Poitrey 2014-03-24 13:27:54 -07:00
commit 710908ed91
2 changed files with 65 additions and 48 deletions

View File

@ -128,7 +128,7 @@ typedef void(^SDWebImageQueryCompletedBlock)(UIImage *image, SDImageCacheType ca
- (void)removeImageForKey:(NSString *)key; - (void)removeImageForKey:(NSString *)key;
/** /**
* Remove the image from memory and optionaly disk cache synchronously * Remove the image from memory and optionally disk cache synchronously
* *
* @param key The unique image cache key * @param key The unique image cache key
* @param fromDisk Also remove cache entry from disk if YES * @param fromDisk Also remove cache entry from disk if YES
@ -141,13 +141,26 @@ typedef void(^SDWebImageQueryCompletedBlock)(UIImage *image, SDImageCacheType ca
- (void)clearMemory; - (void)clearMemory;
/** /**
* Clear all disk cached images * Clear all disk cached images. Non-blocking method - returns immediately.
* @param completionBlock An block that should be executed after cache expiration completes (optional)
*/ */
- (void)clearDisk;
- (void)clearDiskOnCompletion:(void (^)())completion; - (void)clearDiskOnCompletion:(void (^)())completion;
/**
* Clear all disk cached images
* @see clearDiskOnCompletion:
*/
- (void)clearDisk;
/**
* Remove all expired cached image from disk. Non-blocking method - returns immediately.
* @param completionBlock An block that should be executed after cache expiration completes (optional)
*/
- (void)cleanDiskWithCompletionBlock:(void (^)())completionBlock;
/** /**
* Remove all expired cached image from disk * Remove all expired cached image from disk
* @see cleanDiskWithCompletionBlock:
*/ */
- (void)cleanDisk; - (void)cleanDisk;

View File

@ -181,14 +181,11 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
} }
if (data) { if (data) {
// Can't use defaultManager another thread if (![_fileManager fileExistsAtPath:_diskCachePath]) {
NSFileManager *fileManager = [NSFileManager new]; [_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];
if (![fileManager fileExistsAtPath:_diskCachePath]) {
[fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];
} }
[fileManager createFileAtPath:[self defaultCachePathForKey:key] contents:data attributes:nil]; [_fileManager createFileAtPath:[self defaultCachePathForKey:key] contents:data attributes:nil];
} }
}); });
} }
@ -296,7 +293,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
[self.memCache setObject:diskImage forKey:key cost:cost]; [self.memCache setObject:diskImage forKey:key cost:cost];
} }
dispatch_main_sync_safe(^{ dispatch_async(dispatch_get_main_queue(), ^{
doneBlock(diskImage, SDImageCacheTypeDisk); doneBlock(diskImage, SDImageCacheTypeDisk);
}); });
} }
@ -318,7 +315,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
if (fromDisk) { if (fromDisk) {
dispatch_async(self.ioQueue, ^{ dispatch_async(self.ioQueue, ^{
[[NSFileManager defaultManager] removeItemAtPath:[self defaultCachePathForKey:key] error:nil]; [_fileManager removeItemAtPath:[self defaultCachePathForKey:key] error:nil];
}); });
} }
} }
@ -342,14 +339,14 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
- (void)clearDiskOnCompletion:(void (^)())completion - (void)clearDiskOnCompletion:(void (^)())completion
{ {
dispatch_async(self.ioQueue, ^{ dispatch_async(self.ioQueue, ^{
[[NSFileManager defaultManager] removeItemAtPath:self.diskCachePath error:nil]; [_fileManager removeItemAtPath:self.diskCachePath error:nil];
[[NSFileManager defaultManager] createDirectoryAtPath:self.diskCachePath [_fileManager createDirectoryAtPath:self.diskCachePath
withIntermediateDirectories:YES withIntermediateDirectories:YES
attributes:nil attributes:nil
error:NULL]; error:NULL];
if (completion) { if (completion) {
dispatch_main_sync_safe(^{ dispatch_async(dispatch_get_main_queue(), ^{
completion(); completion();
}); });
} }
@ -357,16 +354,19 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
} }
- (void)cleanDisk { - (void)cleanDisk {
[self cleanDiskWithCompletionBlock:nil];
}
- (void)cleanDiskWithCompletionBlock:(void (^)())completionBlock {
dispatch_async(self.ioQueue, ^{ dispatch_async(self.ioQueue, ^{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES]; NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES];
NSArray *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey]; NSArray *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey];
// This enumerator prefetches useful properties for our cache files. // This enumerator prefetches useful properties for our cache files.
NSDirectoryEnumerator *fileEnumerator = [fileManager enumeratorAtURL:diskCacheURL NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtURL:diskCacheURL
includingPropertiesForKeys:resourceKeys includingPropertiesForKeys:resourceKeys
options:NSDirectoryEnumerationSkipsHiddenFiles options:NSDirectoryEnumerationSkipsHiddenFiles
errorHandler:NULL]; errorHandler:NULL];
NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.maxCacheAge]; NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.maxCacheAge];
NSMutableDictionary *cacheFiles = [NSMutableDictionary dictionary]; NSMutableDictionary *cacheFiles = [NSMutableDictionary dictionary];
@ -387,7 +387,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
// Remove files that are older than the expiration date; // Remove files that are older than the expiration date;
NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey]; NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey];
if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) { if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) {
[fileManager removeItemAtURL:fileURL error:nil]; [_fileManager removeItemAtURL:fileURL error:nil];
continue; continue;
} }
@ -411,7 +411,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
// Delete files until we fall below our desired cache size. // Delete files until we fall below our desired cache size.
for (NSURL *fileURL in sortedFiles) { for (NSURL *fileURL in sortedFiles) {
if ([fileManager removeItemAtURL:fileURL error:nil]) { if ([_fileManager removeItemAtURL:fileURL error:nil]) {
NSDictionary *resourceValues = cacheFiles[fileURL]; NSDictionary *resourceValues = cacheFiles[fileURL];
NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey]; NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey];
currentCacheSize -= [totalAllocatedSize unsignedIntegerValue]; currentCacheSize -= [totalAllocatedSize unsignedIntegerValue];
@ -422,6 +422,11 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
} }
} }
} }
if (completionBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock();
});
}
}); });
} }
@ -435,33 +440,33 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
}]; }];
// Start the long-running task and return immediately. // Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self cleanDiskWithCompletionBlock:^{
// Do the work associated with the task, preferably in chunks.
[self cleanDisk];
[application endBackgroundTask:bgTask]; [application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid; bgTask = UIBackgroundTaskInvalid;
}); }];
} }
- (NSUInteger)getSize { - (NSUInteger)getSize {
NSUInteger size = 0; __block NSUInteger size = 0;
NSDirectoryEnumerator *fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:self.diskCachePath]; dispatch_sync(self.ioQueue, ^{
for (NSString *fileName in fileEnumerator) { NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtPath:self.diskCachePath];
NSString *filePath = [self.diskCachePath stringByAppendingPathComponent:fileName]; for (NSString *fileName in fileEnumerator) {
NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil]; NSString *filePath = [self.diskCachePath stringByAppendingPathComponent:fileName];
size += [attrs fileSize]; NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
} size += [attrs fileSize];
}
});
return size; return size;
} }
- (int)getDiskCount { - (int)getDiskCount {
int count = 0; __block int count = 0;
NSDirectoryEnumerator *fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:self.diskCachePath]; dispatch_sync(self.ioQueue, ^{
for (__unused NSString *fileName in fileEnumerator) { NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtPath:self.diskCachePath];
count += 1; for (__unused NSString *fileName in fileEnumerator) {
} count += 1;
}
});
return count; return count;
} }
@ -472,11 +477,10 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
NSUInteger fileCount = 0; NSUInteger fileCount = 0;
NSUInteger totalSize = 0; NSUInteger totalSize = 0;
NSFileManager *fileManager = [NSFileManager defaultManager]; NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtURL:diskCacheURL
NSDirectoryEnumerator *fileEnumerator = [fileManager enumeratorAtURL:diskCacheURL includingPropertiesForKeys:@[NSFileSize]
includingPropertiesForKeys:@[NSFileSize] options:NSDirectoryEnumerationSkipsHiddenFiles
options:NSDirectoryEnumerationSkipsHiddenFiles errorHandler:NULL];
errorHandler:NULL];
for (NSURL *fileURL in fileEnumerator) { for (NSURL *fileURL in fileEnumerator) {
NSNumber *fileSize; NSNumber *fileSize;
@ -486,7 +490,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
} }
if (completionBlock) { if (completionBlock) {
dispatch_main_sync_safe(^{ dispatch_async(dispatch_get_main_queue(), ^{
completionBlock(fileCount, totalSize); completionBlock(fileCount, totalSize);
}); });
} }