TMCache.m 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. #import "TMCache.h"
  2. NSString * const TMCachePrefix = @"com.tumblr.TMCache";
  3. NSString * const TMCacheSharedName = @"TMCacheShared";
  4. @interface TMCache ()
  5. #if OS_OBJECT_USE_OBJC
  6. @property (strong, nonatomic) dispatch_queue_t queue;
  7. #else
  8. @property (assign, nonatomic) dispatch_queue_t queue;
  9. #endif
  10. @end
  11. @implementation TMCache
  12. #pragma mark - Initialization -
  13. #if !OS_OBJECT_USE_OBJC
  14. - (void)dealloc
  15. {
  16. dispatch_release(_queue);
  17. _queue = nil;
  18. }
  19. #endif
  20. - (instancetype)initWithName:(NSString *)name
  21. {
  22. return [self initWithName:name rootPath:[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]];
  23. }
  24. - (instancetype)initWithName:(NSString *)name rootPath:(NSString *)rootPath
  25. {
  26. if (!name)
  27. return nil;
  28. if (self = [super init]) {
  29. _name = [name copy];
  30. NSString *queueName = [[NSString alloc] initWithFormat:@"%@.%p", TMCachePrefix, self];
  31. _queue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_CONCURRENT);
  32. _diskCache = [[TMDiskCache alloc] initWithName:_name rootPath:rootPath];
  33. _memoryCache = [[TMMemoryCache alloc] init];
  34. }
  35. return self;
  36. }
  37. - (NSString *)description
  38. {
  39. return [[NSString alloc] initWithFormat:@"%@.%@.%p", TMCachePrefix, _name, self];
  40. }
  41. + (instancetype)sharedCache
  42. {
  43. static id cache;
  44. static dispatch_once_t predicate;
  45. dispatch_once(&predicate, ^{
  46. cache = [[self alloc] initWithName:TMCacheSharedName];
  47. });
  48. return cache;
  49. }
  50. #pragma mark - Public Asynchronous Methods -
  51. - (void)objectForKey:(NSString *)key block:(TMCacheObjectBlock)block
  52. {
  53. if (!key || !block)
  54. return;
  55. __weak TMCache *weakSelf = self;
  56. dispatch_async(_queue, ^{
  57. TMCache *strongSelf = weakSelf;
  58. if (!strongSelf)
  59. return;
  60. __weak TMCache *weakSelf = strongSelf;
  61. [strongSelf->_memoryCache objectForKey:key block:^(TMMemoryCache *cache, NSString *key, id object) {
  62. TMCache *strongSelf = weakSelf;
  63. if (!strongSelf)
  64. return;
  65. if (object) {
  66. [strongSelf->_diskCache fileURLForKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
  67. // update the access time on disk
  68. }];
  69. __weak TMCache *weakSelf = strongSelf;
  70. dispatch_async(strongSelf->_queue, ^{
  71. TMCache *strongSelf = weakSelf;
  72. if (strongSelf)
  73. block(strongSelf, key, object);
  74. });
  75. } else {
  76. __weak TMCache *weakSelf = strongSelf;
  77. [strongSelf->_diskCache objectForKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
  78. TMCache *strongSelf = weakSelf;
  79. if (!strongSelf)
  80. return;
  81. [strongSelf->_memoryCache setObject:object forKey:key block:nil];
  82. __weak TMCache *weakSelf = strongSelf;
  83. dispatch_async(strongSelf->_queue, ^{
  84. TMCache *strongSelf = weakSelf;
  85. if (strongSelf)
  86. block(strongSelf, key, object);
  87. });
  88. }];
  89. }
  90. }];
  91. });
  92. }
  93. - (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(TMCacheObjectBlock)block
  94. {
  95. if (!key || !object)
  96. return;
  97. dispatch_group_t group = nil;
  98. TMMemoryCacheObjectBlock memBlock = nil;
  99. TMDiskCacheObjectBlock diskBlock = nil;
  100. if (block) {
  101. group = dispatch_group_create();
  102. dispatch_group_enter(group);
  103. dispatch_group_enter(group);
  104. memBlock = ^(TMMemoryCache *cache, NSString *key, id object) {
  105. dispatch_group_leave(group);
  106. };
  107. diskBlock = ^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
  108. dispatch_group_leave(group);
  109. };
  110. }
  111. [_memoryCache setObject:object forKey:key block:memBlock];
  112. [_diskCache setObject:object forKey:key block:diskBlock];
  113. if (group) {
  114. __weak TMCache *weakSelf = self;
  115. dispatch_group_notify(group, _queue, ^{
  116. TMCache *strongSelf = weakSelf;
  117. if (strongSelf)
  118. block(strongSelf, key, object);
  119. });
  120. #if !OS_OBJECT_USE_OBJC
  121. dispatch_release(group);
  122. #endif
  123. }
  124. }
  125. - (void)removeObjectForKey:(NSString *)key block:(TMCacheObjectBlock)block
  126. {
  127. if (!key)
  128. return;
  129. dispatch_group_t group = nil;
  130. TMMemoryCacheObjectBlock memBlock = nil;
  131. TMDiskCacheObjectBlock diskBlock = nil;
  132. if (block) {
  133. group = dispatch_group_create();
  134. dispatch_group_enter(group);
  135. dispatch_group_enter(group);
  136. memBlock = ^(TMMemoryCache *cache, NSString *key, id object) {
  137. dispatch_group_leave(group);
  138. };
  139. diskBlock = ^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
  140. dispatch_group_leave(group);
  141. };
  142. }
  143. [_memoryCache removeObjectForKey:key block:memBlock];
  144. [_diskCache removeObjectForKey:key block:diskBlock];
  145. if (group) {
  146. __weak TMCache *weakSelf = self;
  147. dispatch_group_notify(group, _queue, ^{
  148. TMCache *strongSelf = weakSelf;
  149. if (strongSelf)
  150. block(strongSelf, key, nil);
  151. });
  152. #if !OS_OBJECT_USE_OBJC
  153. dispatch_release(group);
  154. #endif
  155. }
  156. }
  157. - (void)removeAllObjects:(TMCacheBlock)block
  158. {
  159. dispatch_group_t group = nil;
  160. TMMemoryCacheBlock memBlock = nil;
  161. TMDiskCacheBlock diskBlock = nil;
  162. if (block) {
  163. group = dispatch_group_create();
  164. dispatch_group_enter(group);
  165. dispatch_group_enter(group);
  166. memBlock = ^(TMMemoryCache *cache) {
  167. dispatch_group_leave(group);
  168. };
  169. diskBlock = ^(TMDiskCache *cache) {
  170. dispatch_group_leave(group);
  171. };
  172. }
  173. [_memoryCache removeAllObjects:memBlock];
  174. [_diskCache removeAllObjects:diskBlock];
  175. if (group) {
  176. __weak TMCache *weakSelf = self;
  177. dispatch_group_notify(group, _queue, ^{
  178. TMCache *strongSelf = weakSelf;
  179. if (strongSelf)
  180. block(strongSelf);
  181. });
  182. #if !OS_OBJECT_USE_OBJC
  183. dispatch_release(group);
  184. #endif
  185. }
  186. }
  187. - (void)trimToDate:(NSDate *)date block:(TMCacheBlock)block
  188. {
  189. if (!date)
  190. return;
  191. dispatch_group_t group = nil;
  192. TMMemoryCacheBlock memBlock = nil;
  193. TMDiskCacheBlock diskBlock = nil;
  194. if (block) {
  195. group = dispatch_group_create();
  196. dispatch_group_enter(group);
  197. dispatch_group_enter(group);
  198. memBlock = ^(TMMemoryCache *cache) {
  199. dispatch_group_leave(group);
  200. };
  201. diskBlock = ^(TMDiskCache *cache) {
  202. dispatch_group_leave(group);
  203. };
  204. }
  205. [_memoryCache trimToDate:date block:memBlock];
  206. [_diskCache trimToDate:date block:diskBlock];
  207. if (group) {
  208. __weak TMCache *weakSelf = self;
  209. dispatch_group_notify(group, _queue, ^{
  210. TMCache *strongSelf = weakSelf;
  211. if (strongSelf)
  212. block(strongSelf);
  213. });
  214. #if !OS_OBJECT_USE_OBJC
  215. dispatch_release(group);
  216. #endif
  217. }
  218. }
  219. #pragma mark - Public Synchronous Accessors -
  220. - (NSUInteger)diskByteCount
  221. {
  222. __block NSUInteger byteCount = 0;
  223. dispatch_sync([TMDiskCache sharedQueue], ^{
  224. byteCount = self.diskCache.byteCount;
  225. });
  226. return byteCount;
  227. }
  228. #pragma mark - Public Synchronous Methods -
  229. - (id)objectForKey:(NSString *)key
  230. {
  231. if (!key)
  232. return nil;
  233. __block id objectForKey = nil;
  234. dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  235. [self objectForKey:key block:^(TMCache *cache, NSString *key, id object) {
  236. objectForKey = object;
  237. dispatch_semaphore_signal(semaphore);
  238. }];
  239. dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  240. #if !OS_OBJECT_USE_OBJC
  241. dispatch_release(semaphore);
  242. #endif
  243. return objectForKey;
  244. }
  245. - (void)setObject:(id <NSCoding>)object forKey:(NSString *)key
  246. {
  247. if (!object || !key)
  248. return;
  249. dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  250. [self setObject:object forKey:key block:^(TMCache *cache, NSString *key, id object) {
  251. dispatch_semaphore_signal(semaphore);
  252. }];
  253. dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  254. #if !OS_OBJECT_USE_OBJC
  255. dispatch_release(semaphore);
  256. #endif
  257. }
  258. - (void)removeObjectForKey:(NSString *)key
  259. {
  260. if (!key)
  261. return;
  262. dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  263. [self removeObjectForKey:key block:^(TMCache *cache, NSString *key, id object) {
  264. dispatch_semaphore_signal(semaphore);
  265. }];
  266. dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  267. #if !OS_OBJECT_USE_OBJC
  268. dispatch_release(semaphore);
  269. #endif
  270. }
  271. - (void)trimToDate:(NSDate *)date
  272. {
  273. if (!date)
  274. return;
  275. dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  276. [self trimToDate:date block:^(TMCache *cache) {
  277. dispatch_semaphore_signal(semaphore);
  278. }];
  279. dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  280. #if !OS_OBJECT_USE_OBJC
  281. dispatch_release(semaphore);
  282. #endif
  283. }
  284. - (void)removeAllObjects
  285. {
  286. dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  287. [self removeAllObjects:^(TMCache *cache) {
  288. dispatch_semaphore_signal(semaphore);
  289. }];
  290. dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  291. #if !OS_OBJECT_USE_OBJC
  292. dispatch_release(semaphore);
  293. #endif
  294. }
  295. @end
  296. // HC SVNT DRACONES