Browse files

adds 'queue-jumping' for file system-related tasks.

  • Loading branch information...
1 parent 6647323 commit 8b809536aa3c68ddfa3f4469e8697e585a8f9a21 @artgillespie committed Aug 22, 2013
Showing with 23 additions and 13 deletions.
  1. +5 −2 OGImage/OGImageCache.h
  2. +18 −11 OGImage/OGImageCache.m
View
7 OGImage/OGImageCache.h
@@ -47,11 +47,14 @@ typedef void (^OGImageCacheCompletionBlock)(__OGImage *image);
- (void)purgeMemoryCacheForKey:(NSString *)key andWait:(BOOL)wait;
/**
+ *
+ */
+
+/**
* Remove cached images from disk that haven't been accessed since `date`
* If `wait` is `YES` this will block the calling thread until the purge
* is complete.
*/
-- (void)purgeDiskCacheWithDate:(NSDate *)date wait:(BOOL)wait;
-
+- (void)purgeDiskCacheOfImagesLastAccessedBefore:(NSDate *)date;
@end
View
29 OGImage/OGImageCache.m
@@ -38,6 +38,7 @@
@implementation OGImageCache {
NSCache *_memoryCache;
+ dispatch_queue_t _cacheFileReadQueue;
dispatch_queue_t _cacheFileTasksQueue;
}
@@ -69,8 +70,18 @@ - (id)init {
if (self) {
_memoryCache = [[NSCache alloc] init];
[_memoryCache setName:@"com.origamilabs.OGImageCache"];
+ /*
+ * We use the 'queue-jumping' pattern outlined in WWDC 2012 Session 201: "Mastering Grand Central Dispatch"
+ * We place lower-priority tasks (writing, purging) on a serial queue that has its
+ * target queue set to our high-priority (read) queue. Whenever we submit a high-priority
+ * block, we suspend the lower-priority queue for the duration of the block.
+ *
+ * This way, writes and purges never cause cache reads to wait in the queue.
+ */
+ _cacheFileReadQueue = dispatch_queue_create("com.origamilabs.OGImageCache.read", DISPATCH_QUEUE_SERIAL);
+ dispatch_set_target_queue(_cacheFileReadQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
_cacheFileTasksQueue = dispatch_queue_create("com.origamilabs.OGImageCache.filetasks", DISPATCH_QUEUE_SERIAL);
- dispatch_set_target_queue(_cacheFileTasksQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
+ dispatch_set_target_queue(_cacheFileTasksQueue, _cacheFileReadQueue);
}
return self;
}
@@ -83,7 +94,8 @@ - (void)imageForKey:(NSString *)key block:(OGImageCacheCompletionBlock)block {
block(image);
return;
}
- dispatch_async(_cacheFileTasksQueue, ^{
+ dispatch_suspend(_cacheFileTasksQueue);
+ dispatch_async(_cacheFileReadQueue, ^{
// Check to see if the image is cached locally
NSString *cachePath = [OGImageCache filePathForKey:(key)];
__OGImage *image = [[__OGImage alloc] initWithDataAtURL:[NSURL fileURLWithPath:cachePath]];
@@ -95,6 +107,7 @@ - (void)imageForKey:(NSString *)key block:(OGImageCacheCompletionBlock)block {
dispatch_async(dispatch_get_main_queue(), ^{
block(image);
});
+ dispatch_resume(_cacheFileTasksQueue);
});
}
@@ -154,8 +167,8 @@ - (void)purgeMemoryCacheForKey:(NSString *)key andWait:(BOOL)wait {
[_memoryCache removeObjectForKey:key];
}
-- (void)purgeDiskCacheWithDate:(NSDate *)date wait:(BOOL)wait {
- void (^purgeFilesBlock)(void) = ^{
+- (void)purgeDiskCacheOfImagesLastAccessedBefore:(NSDate *)date {
+ dispatch_async(_cacheFileTasksQueue, ^{
NSURL *cacheURL = OGImageCacheURL();
for (NSURL *fileURL in [[NSFileManager defaultManager] enumeratorAtURL:cacheURL includingPropertiesForKeys:@[NSURLContentAccessDateKey] options:NSDirectoryEnumerationSkipsHiddenFiles errorHandler:nil]) {
NSDate *accessDate;
@@ -166,13 +179,7 @@ - (void)purgeDiskCacheWithDate:(NSDate *)date wait:(BOOL)wait {
[[NSFileManager defaultManager] removeItemAtURL:fileURL error:nil];
}
}
- };
-
- if (YES == wait) {
- dispatch_sync(_cacheFileTasksQueue, purgeFilesBlock);
- } else {
- dispatch_async(_cacheFileTasksQueue, purgeFilesBlock);
- }
+ });
}
@end

0 comments on commit 8b80953

Please sign in to comment.