Authored by Olivier Poitrey

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

Various GCD related fixes for SDImageCache
@@ -128,7 +128,7 @@ typedef void(^SDWebImageQueryCompletedBlock)(UIImage *image, SDImageCacheType ca @@ -128,7 +128,7 @@ typedef void(^SDWebImageQueryCompletedBlock)(UIImage *image, SDImageCacheType ca
128 - (void)removeImageForKey:(NSString *)key; 128 - (void)removeImageForKey:(NSString *)key;
129 129
130 /** 130 /**
131 - * Remove the image from memory and optionaly disk cache synchronously 131 + * Remove the image from memory and optionally disk cache synchronously
132 * 132 *
133 * @param key The unique image cache key 133 * @param key The unique image cache key
134 * @param fromDisk Also remove cache entry from disk if YES 134 * @param fromDisk Also remove cache entry from disk if YES
@@ -141,13 +141,26 @@ typedef void(^SDWebImageQueryCompletedBlock)(UIImage *image, SDImageCacheType ca @@ -141,13 +141,26 @@ typedef void(^SDWebImageQueryCompletedBlock)(UIImage *image, SDImageCacheType ca
141 - (void)clearMemory; 141 - (void)clearMemory;
142 142
143 /** 143 /**
  144 + * Clear all disk cached images. Non-blocking method - returns immediately.
  145 + * @param completionBlock An block that should be executed after cache expiration completes (optional)
  146 + */
  147 +- (void)clearDiskOnCompletion:(void (^)())completion;
  148 +
  149 +/**
144 * Clear all disk cached images 150 * Clear all disk cached images
  151 + * @see clearDiskOnCompletion:
145 */ 152 */
146 - (void)clearDisk; 153 - (void)clearDisk;
147 -- (void)clearDiskOnCompletion:(void (^)())completion; 154 +
  155 +/**
  156 + * Remove all expired cached image from disk. Non-blocking method - returns immediately.
  157 + * @param completionBlock An block that should be executed after cache expiration completes (optional)
  158 + */
  159 +- (void)cleanDiskWithCompletionBlock:(void (^)())completionBlock;
148 160
149 /** 161 /**
150 * Remove all expired cached image from disk 162 * Remove all expired cached image from disk
  163 + * @see cleanDiskWithCompletionBlock:
151 */ 164 */
152 - (void)cleanDisk; 165 - (void)cleanDisk;
153 166
@@ -181,14 +181,11 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { @@ -181,14 +181,11 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
181 } 181 }
182 182
183 if (data) { 183 if (data) {
184 - // Can't use defaultManager another thread  
185 - NSFileManager *fileManager = [NSFileManager new];  
186 -  
187 - if (![fileManager fileExistsAtPath:_diskCachePath]) {  
188 - [fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL]; 184 + if (![_fileManager fileExistsAtPath:_diskCachePath]) {
  185 + [_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];
189 } 186 }
190 187
191 - [fileManager createFileAtPath:[self defaultCachePathForKey:key] contents:data attributes:nil]; 188 + [_fileManager createFileAtPath:[self defaultCachePathForKey:key] contents:data attributes:nil];
192 } 189 }
193 }); 190 });
194 } 191 }
@@ -296,7 +293,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { @@ -296,7 +293,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
296 [self.memCache setObject:diskImage forKey:key cost:cost]; 293 [self.memCache setObject:diskImage forKey:key cost:cost];
297 } 294 }
298 295
299 - dispatch_main_sync_safe(^{ 296 + dispatch_async(dispatch_get_main_queue(), ^{
300 doneBlock(diskImage, SDImageCacheTypeDisk); 297 doneBlock(diskImage, SDImageCacheTypeDisk);
301 }); 298 });
302 } 299 }
@@ -318,7 +315,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { @@ -318,7 +315,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
318 315
319 if (fromDisk) { 316 if (fromDisk) {
320 dispatch_async(self.ioQueue, ^{ 317 dispatch_async(self.ioQueue, ^{
321 - [[NSFileManager defaultManager] removeItemAtPath:[self defaultCachePathForKey:key] error:nil]; 318 + [_fileManager removeItemAtPath:[self defaultCachePathForKey:key] error:nil];
322 }); 319 });
323 } 320 }
324 } 321 }
@@ -342,14 +339,14 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { @@ -342,14 +339,14 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
342 - (void)clearDiskOnCompletion:(void (^)())completion 339 - (void)clearDiskOnCompletion:(void (^)())completion
343 { 340 {
344 dispatch_async(self.ioQueue, ^{ 341 dispatch_async(self.ioQueue, ^{
345 - [[NSFileManager defaultManager] removeItemAtPath:self.diskCachePath error:nil];  
346 - [[NSFileManager defaultManager] createDirectoryAtPath:self.diskCachePath  
347 - withIntermediateDirectories:YES  
348 - attributes:nil  
349 - error:NULL]; 342 + [_fileManager removeItemAtPath:self.diskCachePath error:nil];
  343 + [_fileManager createDirectoryAtPath:self.diskCachePath
  344 + withIntermediateDirectories:YES
  345 + attributes:nil
  346 + error:NULL];
350 347
351 if (completion) { 348 if (completion) {
352 - dispatch_main_sync_safe(^{ 349 + dispatch_async(dispatch_get_main_queue(), ^{
353 completion(); 350 completion();
354 }); 351 });
355 } 352 }
@@ -357,16 +354,19 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { @@ -357,16 +354,19 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
357 } 354 }
358 355
359 - (void)cleanDisk { 356 - (void)cleanDisk {
  357 + [self cleanDiskWithCompletionBlock:nil];
  358 +}
  359 +
  360 +- (void)cleanDiskWithCompletionBlock:(void (^)())completionBlock {
360 dispatch_async(self.ioQueue, ^{ 361 dispatch_async(self.ioQueue, ^{
361 - NSFileManager *fileManager = [NSFileManager defaultManager];  
362 NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES]; 362 NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES];
363 NSArray *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey]; 363 NSArray *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey];
364 364
365 // This enumerator prefetches useful properties for our cache files. 365 // This enumerator prefetches useful properties for our cache files.
366 - NSDirectoryEnumerator *fileEnumerator = [fileManager enumeratorAtURL:diskCacheURL  
367 - includingPropertiesForKeys:resourceKeys  
368 - options:NSDirectoryEnumerationSkipsHiddenFiles  
369 - errorHandler:NULL]; 366 + NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtURL:diskCacheURL
  367 + includingPropertiesForKeys:resourceKeys
  368 + options:NSDirectoryEnumerationSkipsHiddenFiles
  369 + errorHandler:NULL];
370 370
371 NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.maxCacheAge]; 371 NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.maxCacheAge];
372 NSMutableDictionary *cacheFiles = [NSMutableDictionary dictionary]; 372 NSMutableDictionary *cacheFiles = [NSMutableDictionary dictionary];
@@ -387,7 +387,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { @@ -387,7 +387,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
387 // Remove files that are older than the expiration date; 387 // Remove files that are older than the expiration date;
388 NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey]; 388 NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey];
389 if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) { 389 if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) {
390 - [fileManager removeItemAtURL:fileURL error:nil]; 390 + [_fileManager removeItemAtURL:fileURL error:nil];
391 continue; 391 continue;
392 } 392 }
393 393
@@ -411,7 +411,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { @@ -411,7 +411,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
411 411
412 // Delete files until we fall below our desired cache size. 412 // Delete files until we fall below our desired cache size.
413 for (NSURL *fileURL in sortedFiles) { 413 for (NSURL *fileURL in sortedFiles) {
414 - if ([fileManager removeItemAtURL:fileURL error:nil]) { 414 + if ([_fileManager removeItemAtURL:fileURL error:nil]) {
415 NSDictionary *resourceValues = cacheFiles[fileURL]; 415 NSDictionary *resourceValues = cacheFiles[fileURL];
416 NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey]; 416 NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey];
417 currentCacheSize -= [totalAllocatedSize unsignedIntegerValue]; 417 currentCacheSize -= [totalAllocatedSize unsignedIntegerValue];
@@ -422,6 +422,11 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { @@ -422,6 +422,11 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
422 } 422 }
423 } 423 }
424 } 424 }
  425 + if (completionBlock) {
  426 + dispatch_async(dispatch_get_main_queue(), ^{
  427 + completionBlock();
  428 + });
  429 + }
425 }); 430 });
426 } 431 }
427 432
@@ -435,33 +440,33 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { @@ -435,33 +440,33 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
435 }]; 440 }];
436 441
437 // Start the long-running task and return immediately. 442 // Start the long-running task and return immediately.
438 - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
439 - // Do the work associated with the task, preferably in chunks.  
440 - [self cleanDisk];  
441 - 443 + [self cleanDiskWithCompletionBlock:^{
442 [application endBackgroundTask:bgTask]; 444 [application endBackgroundTask:bgTask];
443 bgTask = UIBackgroundTaskInvalid; 445 bgTask = UIBackgroundTaskInvalid;
444 - }); 446 + }];
445 } 447 }
446 448
447 - (NSUInteger)getSize { 449 - (NSUInteger)getSize {
448 - NSUInteger size = 0;  
449 - NSDirectoryEnumerator *fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:self.diskCachePath];  
450 - for (NSString *fileName in fileEnumerator) {  
451 - NSString *filePath = [self.diskCachePath stringByAppendingPathComponent:fileName];  
452 - NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];  
453 - size += [attrs fileSize];  
454 - } 450 + __block NSUInteger size = 0;
  451 + dispatch_sync(self.ioQueue, ^{
  452 + NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtPath:self.diskCachePath];
  453 + for (NSString *fileName in fileEnumerator) {
  454 + NSString *filePath = [self.diskCachePath stringByAppendingPathComponent:fileName];
  455 + NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
  456 + size += [attrs fileSize];
  457 + }
  458 + });
455 return size; 459 return size;
456 } 460 }
457 461
458 - (int)getDiskCount { 462 - (int)getDiskCount {
459 - int count = 0;  
460 - NSDirectoryEnumerator *fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:self.diskCachePath];  
461 - for (__unused NSString *fileName in fileEnumerator) {  
462 - count += 1;  
463 - }  
464 - 463 + __block int count = 0;
  464 + dispatch_sync(self.ioQueue, ^{
  465 + NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtPath:self.diskCachePath];
  466 + for (__unused NSString *fileName in fileEnumerator) {
  467 + count += 1;
  468 + }
  469 + });
465 return count; 470 return count;
466 } 471 }
467 472
@@ -472,11 +477,10 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { @@ -472,11 +477,10 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
472 NSUInteger fileCount = 0; 477 NSUInteger fileCount = 0;
473 NSUInteger totalSize = 0; 478 NSUInteger totalSize = 0;
474 479
475 - NSFileManager *fileManager = [NSFileManager defaultManager];  
476 - NSDirectoryEnumerator *fileEnumerator = [fileManager enumeratorAtURL:diskCacheURL  
477 - includingPropertiesForKeys:@[NSFileSize]  
478 - options:NSDirectoryEnumerationSkipsHiddenFiles  
479 - errorHandler:NULL]; 480 + NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtURL:diskCacheURL
  481 + includingPropertiesForKeys:@[NSFileSize]
  482 + options:NSDirectoryEnumerationSkipsHiddenFiles
  483 + errorHandler:NULL];
480 484
481 for (NSURL *fileURL in fileEnumerator) { 485 for (NSURL *fileURL in fileEnumerator) {
482 NSNumber *fileSize; 486 NSNumber *fileSize;
@@ -486,7 +490,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { @@ -486,7 +490,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) {
486 } 490 }
487 491
488 if (completionBlock) { 492 if (completionBlock) {
489 - dispatch_main_sync_safe(^{ 493 + dispatch_async(dispatch_get_main_queue(), ^{
490 completionBlock(fileCount, totalSize); 494 completionBlock(fileCount, totalSize);
491 }); 495 });
492 } 496 }