ReaderThumbCache.m 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. //
  2. // ReaderThumbCache.m
  3. // Reader v2.9.0
  4. //
  5. // Created by Julius Oklamcak on 2011-09-01.
  6. // Copyright © 2011-2015 Julius Oklamcak. All rights reserved.
  7. //
  8. // Permission is hereby granted, free of charge, to any person obtaining a copy
  9. // of this software and associated documentation files (the "Software"), to deal
  10. // in the Software without restriction, including without limitation the rights to
  11. // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  12. // of the Software, and to permit persons to whom the Software is furnished to
  13. // do so, subject to the following conditions:
  14. //
  15. // The above copyright notice and this permission notice shall be included in all
  16. // copies or substantial portions of the Software.
  17. //
  18. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  23. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24. //
  25. #import "ReaderThumbCache.h"
  26. #import "ReaderThumbQueue.h"
  27. #import "ReaderThumbFetch.h"
  28. #import "ReaderThumbView.h"
  29. @implementation ReaderThumbCache
  30. {
  31. NSCache *thumbCache;
  32. }
  33. #pragma mark - Constants
  34. #define CACHE_SIZE 2097152
  35. #pragma mark - ReaderThumbCache class methods
  36. + (ReaderThumbCache *)sharedInstance
  37. {
  38. static dispatch_once_t predicate = 0;
  39. static ReaderThumbCache *object = nil; // Object
  40. dispatch_once(&predicate, ^{ object = [self new]; });
  41. return object; // ReaderThumbCache singleton
  42. }
  43. + (NSString *)appCachesPath
  44. {
  45. static dispatch_once_t predicate = 0;
  46. static NSString *theCachesPath = nil; // Application caches path string
  47. dispatch_once(&predicate, // Save a copy of the application caches path the first time it is needed
  48. ^{
  49. NSArray *cachesPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
  50. theCachesPath = [[cachesPaths objectAtIndex:0] copy]; // Keep a copy for later abusage
  51. });
  52. return theCachesPath;
  53. }
  54. + (NSString *)thumbCachePathForGUID:(NSString *)guid
  55. {
  56. NSString *cachesPath = [ReaderThumbCache appCachesPath]; // Caches path
  57. return [cachesPath stringByAppendingPathComponent:guid]; // Append GUID
  58. }
  59. + (void)createThumbCacheWithGUID:(NSString *)guid
  60. {
  61. NSFileManager *fileManager = [NSFileManager new]; // File manager instance
  62. NSString *cachePath = [ReaderThumbCache thumbCachePathForGUID:guid]; // Thumb cache path
  63. [fileManager createDirectoryAtPath:cachePath withIntermediateDirectories:NO attributes:nil error:NULL];
  64. }
  65. + (void)removeThumbCacheWithGUID:(NSString *)guid
  66. {
  67. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
  68. ^{
  69. NSFileManager *fileManager = [NSFileManager new]; // File manager instance
  70. NSString *cachePath = [ReaderThumbCache thumbCachePathForGUID:guid]; // Thumb cache path
  71. [fileManager removeItemAtPath:cachePath error:NULL]; // Remove thumb cache directory
  72. });
  73. }
  74. + (void)touchThumbCacheWithGUID:(NSString *)guid
  75. {
  76. NSFileManager *fileManager = [NSFileManager new]; // File manager instance
  77. NSString *cachePath = [ReaderThumbCache thumbCachePathForGUID:guid]; // Thumb cache path
  78. NSDictionary *attributes = [NSDictionary dictionaryWithObject:[NSDate date] forKey:NSFileModificationDate];
  79. [fileManager setAttributes:attributes ofItemAtPath:cachePath error:NULL]; // New modification date
  80. }
  81. + (void)purgeThumbCachesOlderThan:(NSTimeInterval)age
  82. {
  83. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
  84. ^{
  85. NSDate *now = [NSDate date]; // Right about now time
  86. NSString *cachesPath = [ReaderThumbCache appCachesPath]; // Caches path
  87. NSFileManager *fileManager = [NSFileManager new]; // File manager instance
  88. NSArray *cachesList = [fileManager contentsOfDirectoryAtPath:cachesPath error:NULL];
  89. if (cachesList != nil) // Process caches directory contents
  90. {
  91. for (NSString *cacheName in cachesList) // Enumerate directory contents
  92. {
  93. if (cacheName.length == 36) // This is a very hacky cache ident kludge
  94. {
  95. NSString *cachePath = [cachesPath stringByAppendingPathComponent:cacheName];
  96. NSDictionary *attributes = [fileManager attributesOfItemAtPath:cachePath error:NULL];
  97. NSDate *cacheDate = [attributes objectForKey:NSFileModificationDate]; // Cache date
  98. NSTimeInterval seconds = [now timeIntervalSinceDate:cacheDate]; // Cache age
  99. if (seconds > age) // Older than so remove the thumb cache
  100. {
  101. [fileManager removeItemAtPath:cachePath error:NULL];
  102. #ifdef DEBUG
  103. NSLog(@"%s purged %@", __FUNCTION__, cacheName);
  104. #endif
  105. }
  106. }
  107. }
  108. }
  109. });
  110. }
  111. #pragma mark - ReaderThumbCache instance methods
  112. - (instancetype)init
  113. {
  114. if ((self = [super init])) // Initialize
  115. {
  116. thumbCache = [NSCache new]; // Cache
  117. [thumbCache setName:@"ReaderThumbCache"];
  118. [thumbCache setTotalCostLimit:CACHE_SIZE];
  119. }
  120. return self;
  121. }
  122. - (id)thumbRequest:(ReaderThumbRequest *)request priority:(BOOL)priority
  123. {
  124. @synchronized(thumbCache) // Mutex lock
  125. {
  126. id object = [thumbCache objectForKey:request.cacheKey];
  127. if (object == nil) // Thumb object does not yet exist in the cache
  128. {
  129. object = [NSNull null]; // Return an NSNull thumb placeholder object
  130. [thumbCache setObject:object forKey:request.cacheKey cost:2]; // Cache the placeholder object
  131. ReaderThumbFetch *thumbFetch = [[ReaderThumbFetch alloc] initWithRequest:request]; // Create a thumb fetch operation
  132. [thumbFetch setQueuePriority:(priority ? NSOperationQueuePriorityNormal : NSOperationQueuePriorityLow)]; // Queue priority
  133. request.thumbView.operation = thumbFetch; //[thumbFetch setThreadPriority:(priority ? 0.55 : 0.35)]; // Thread priority
  134. [[ReaderThumbQueue sharedInstance] addLoadOperation:thumbFetch]; // Queue the operation
  135. }
  136. return object; // NSNull or UIImage
  137. }
  138. }
  139. - (void)setObject:(UIImage *)image forKey:(NSString *)key
  140. {
  141. @synchronized(thumbCache) // Mutex lock
  142. {
  143. NSUInteger bytes = (image.size.width * image.size.height * 4.0f);
  144. [thumbCache setObject:image forKey:key cost:bytes]; // Cache image
  145. }
  146. }
  147. - (void)removeObjectForKey:(NSString *)key
  148. {
  149. @synchronized(thumbCache) // Mutex lock
  150. {
  151. [thumbCache removeObjectForKey:key];
  152. }
  153. }
  154. - (void)removeNullForKey:(NSString *)key
  155. {
  156. @synchronized(thumbCache) // Mutex lock
  157. {
  158. id object = [thumbCache objectForKey:key];
  159. if ([object isMemberOfClass:[NSNull class]])
  160. {
  161. [thumbCache removeObjectForKey:key];
  162. }
  163. }
  164. }
  165. - (void)removeAllObjects
  166. {
  167. @synchronized(thumbCache) // Mutex lock
  168. {
  169. [thumbCache removeAllObjects];
  170. }
  171. }
  172. @end