PINMemoryCache.m 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. // PINCache is a modified version of TMCache
  2. // Modifications by Garrett Moon
  3. // Copyright (c) 2015 Pinterest. All rights reserved.
  4. #import "PINMemoryCache.h"
  5. #import <pthread.h>
  6. #import <PINOperation.h>
  7. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
  8. #import <UIKit/UIKit.h>
  9. #endif
  10. static NSString * const PINMemoryCachePrefix = @"com.pinterest.PINMemoryCache";
  11. static NSString * const PINMemoryCacheSharedName = @"PINMemoryCacheSharedName";
  12. @interface PINMemoryCache ()
  13. @property (copy, nonatomic) NSString *name;
  14. @property (strong, nonatomic) PINOperationQueue *operationQueue;
  15. @property (assign, nonatomic) pthread_mutex_t mutex;
  16. @property (strong, nonatomic) NSMutableDictionary *dictionary;
  17. @property (strong, nonatomic) NSMutableDictionary *dates;
  18. @property (strong, nonatomic) NSMutableDictionary *costs;
  19. @end
  20. @implementation PINMemoryCache
  21. @synthesize name = _name;
  22. @synthesize ageLimit = _ageLimit;
  23. @synthesize costLimit = _costLimit;
  24. @synthesize totalCost = _totalCost;
  25. @synthesize ttlCache = _ttlCache;
  26. @synthesize willAddObjectBlock = _willAddObjectBlock;
  27. @synthesize willRemoveObjectBlock = _willRemoveObjectBlock;
  28. @synthesize willRemoveAllObjectsBlock = _willRemoveAllObjectsBlock;
  29. @synthesize didAddObjectBlock = _didAddObjectBlock;
  30. @synthesize didRemoveObjectBlock = _didRemoveObjectBlock;
  31. @synthesize didRemoveAllObjectsBlock = _didRemoveAllObjectsBlock;
  32. @synthesize didReceiveMemoryWarningBlock = _didReceiveMemoryWarningBlock;
  33. @synthesize didEnterBackgroundBlock = _didEnterBackgroundBlock;
  34. #pragma mark - Initialization -
  35. - (void)dealloc
  36. {
  37. [[NSNotificationCenter defaultCenter] removeObserver:self];
  38. __unused int result = pthread_mutex_destroy(&_mutex);
  39. NSCAssert(result == 0, @"Failed to destroy lock in PINMemoryCache %p. Code: %d", (void *)self, result);
  40. }
  41. - (instancetype)init
  42. {
  43. return [self initWithOperationQueue:[PINOperationQueue sharedOperationQueue]];
  44. }
  45. - (instancetype)initWithOperationQueue:(PINOperationQueue *)operationQueue
  46. {
  47. return [self initWithName:PINMemoryCacheSharedName operationQueue:operationQueue];
  48. }
  49. - (instancetype)initWithName:(NSString *)name operationQueue:(PINOperationQueue *)operationQueue
  50. {
  51. if (self = [super init]) {
  52. __unused int result = pthread_mutex_init(&_mutex, NULL);
  53. NSAssert(result == 0, @"Failed to init lock in PINMemoryCache %@. Code: %d", self, result);
  54. _name = [name copy];
  55. _operationQueue = operationQueue;
  56. _dictionary = [[NSMutableDictionary alloc] init];
  57. _dates = [[NSMutableDictionary alloc] init];
  58. _costs = [[NSMutableDictionary alloc] init];
  59. _willAddObjectBlock = nil;
  60. _willRemoveObjectBlock = nil;
  61. _willRemoveAllObjectsBlock = nil;
  62. _didAddObjectBlock = nil;
  63. _didRemoveObjectBlock = nil;
  64. _didRemoveAllObjectsBlock = nil;
  65. _didReceiveMemoryWarningBlock = nil;
  66. _didEnterBackgroundBlock = nil;
  67. _ageLimit = 0.0;
  68. _costLimit = 0;
  69. _totalCost = 0;
  70. _removeAllObjectsOnMemoryWarning = YES;
  71. _removeAllObjectsOnEnteringBackground = YES;
  72. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0 && !TARGET_OS_WATCH
  73. [[NSNotificationCenter defaultCenter] addObserver:self
  74. selector:@selector(didReceiveEnterBackgroundNotification:)
  75. name:UIApplicationDidEnterBackgroundNotification
  76. object:nil];
  77. [[NSNotificationCenter defaultCenter] addObserver:self
  78. selector:@selector(didReceiveMemoryWarningNotification:)
  79. name:UIApplicationDidReceiveMemoryWarningNotification
  80. object:nil];
  81. #endif
  82. }
  83. return self;
  84. }
  85. + (PINMemoryCache *)sharedCache
  86. {
  87. static PINMemoryCache *cache;
  88. static dispatch_once_t predicate;
  89. dispatch_once(&predicate, ^{
  90. cache = [[PINMemoryCache alloc] init];
  91. });
  92. return cache;
  93. }
  94. #pragma mark - Private Methods -
  95. - (void)didReceiveMemoryWarningNotification:(NSNotification *)notification {
  96. if (self.removeAllObjectsOnMemoryWarning)
  97. [self removeAllObjectsAsync:nil];
  98. __weak PINMemoryCache *weakSelf = self;
  99. [self.operationQueue addOperation:^{
  100. PINMemoryCache *strongSelf = weakSelf;
  101. if (!strongSelf) {
  102. return;
  103. }
  104. [strongSelf lock];
  105. PINCacheBlock didReceiveMemoryWarningBlock = strongSelf->_didReceiveMemoryWarningBlock;
  106. [strongSelf unlock];
  107. if (didReceiveMemoryWarningBlock)
  108. didReceiveMemoryWarningBlock(strongSelf);
  109. } withPriority:PINOperationQueuePriorityHigh];
  110. }
  111. - (void)didReceiveEnterBackgroundNotification:(NSNotification *)notification
  112. {
  113. if (self.removeAllObjectsOnEnteringBackground)
  114. [self removeAllObjectsAsync:nil];
  115. __weak PINMemoryCache *weakSelf = self;
  116. [self.operationQueue addOperation:^{
  117. PINMemoryCache *strongSelf = weakSelf;
  118. if (!strongSelf) {
  119. return;
  120. }
  121. [strongSelf lock];
  122. PINCacheBlock didEnterBackgroundBlock = strongSelf->_didEnterBackgroundBlock;
  123. [strongSelf unlock];
  124. if (didEnterBackgroundBlock)
  125. didEnterBackgroundBlock(strongSelf);
  126. } withPriority:PINOperationQueuePriorityHigh];
  127. }
  128. - (void)removeObjectAndExecuteBlocksForKey:(NSString *)key
  129. {
  130. [self lock];
  131. id object = _dictionary[key];
  132. NSNumber *cost = _costs[key];
  133. PINCacheObjectBlock willRemoveObjectBlock = _willRemoveObjectBlock;
  134. PINCacheObjectBlock didRemoveObjectBlock = _didRemoveObjectBlock;
  135. [self unlock];
  136. if (willRemoveObjectBlock)
  137. willRemoveObjectBlock(self, key, object);
  138. [self lock];
  139. if (cost)
  140. _totalCost -= [cost unsignedIntegerValue];
  141. [_dictionary removeObjectForKey:key];
  142. [_dates removeObjectForKey:key];
  143. [_costs removeObjectForKey:key];
  144. [self unlock];
  145. if (didRemoveObjectBlock)
  146. didRemoveObjectBlock(self, key, nil);
  147. }
  148. - (void)trimMemoryToDate:(NSDate *)trimDate
  149. {
  150. [self lock];
  151. NSArray *keysSortedByDate = [_dates keysSortedByValueUsingSelector:@selector(compare:)];
  152. NSDictionary *dates = [_dates copy];
  153. [self unlock];
  154. for (NSString *key in keysSortedByDate) { // oldest objects first
  155. NSDate *accessDate = dates[key];
  156. if (!accessDate)
  157. continue;
  158. if ([accessDate compare:trimDate] == NSOrderedAscending) { // older than trim date
  159. [self removeObjectAndExecuteBlocksForKey:key];
  160. } else {
  161. break;
  162. }
  163. }
  164. }
  165. - (void)trimToCostLimit:(NSUInteger)limit
  166. {
  167. NSUInteger totalCost = 0;
  168. [self lock];
  169. totalCost = _totalCost;
  170. NSArray *keysSortedByCost = [_costs keysSortedByValueUsingSelector:@selector(compare:)];
  171. [self unlock];
  172. if (totalCost <= limit) {
  173. return;
  174. }
  175. for (NSString *key in [keysSortedByCost reverseObjectEnumerator]) { // costliest objects first
  176. [self removeObjectAndExecuteBlocksForKey:key];
  177. [self lock];
  178. totalCost = _totalCost;
  179. [self unlock];
  180. if (totalCost <= limit)
  181. break;
  182. }
  183. }
  184. - (void)trimToCostLimitByDate:(NSUInteger)limit
  185. {
  186. NSUInteger totalCost = 0;
  187. [self lock];
  188. totalCost = _totalCost;
  189. NSArray *keysSortedByDate = [_dates keysSortedByValueUsingSelector:@selector(compare:)];
  190. [self unlock];
  191. if (totalCost <= limit)
  192. return;
  193. for (NSString *key in keysSortedByDate) { // oldest objects first
  194. [self removeObjectAndExecuteBlocksForKey:key];
  195. [self lock];
  196. totalCost = _totalCost;
  197. [self unlock];
  198. if (totalCost <= limit)
  199. break;
  200. }
  201. }
  202. - (void)trimToAgeLimitRecursively
  203. {
  204. [self lock];
  205. NSTimeInterval ageLimit = _ageLimit;
  206. [self unlock];
  207. if (ageLimit == 0.0)
  208. return;
  209. NSDate *date = [[NSDate alloc] initWithTimeIntervalSinceNow:-ageLimit];
  210. [self trimMemoryToDate:date];
  211. __weak PINMemoryCache *weakSelf = self;
  212. dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(ageLimit * NSEC_PER_SEC));
  213. dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
  214. PINMemoryCache *strongSelf = weakSelf;
  215. [strongSelf.operationQueue addOperation:^{
  216. PINMemoryCache *strongSelf = weakSelf;
  217. [strongSelf trimToAgeLimitRecursively];
  218. } withPriority:PINOperationQueuePriorityHigh];
  219. });
  220. }
  221. #pragma mark - Public Asynchronous Methods -
  222. - (void)containsObjectForKeyAsync:(NSString *)key completion:(PINCacheObjectContainmentBlock)block
  223. {
  224. if (!key || !block)
  225. return;
  226. __weak PINMemoryCache *weakSelf = self;
  227. [self.operationQueue addOperation:^{
  228. PINMemoryCache *strongSelf = weakSelf;
  229. BOOL containsObject = [strongSelf containsObjectForKey:key];
  230. block(containsObject);
  231. } withPriority:PINOperationQueuePriorityHigh];
  232. }
  233. - (void)objectForKeyAsync:(NSString *)key completion:(PINCacheObjectBlock)block
  234. {
  235. if (block == nil) {
  236. return;
  237. }
  238. __weak PINMemoryCache *weakSelf = self;
  239. [self.operationQueue addOperation:^{
  240. PINMemoryCache *strongSelf = weakSelf;
  241. id object = [strongSelf objectForKey:key];
  242. block(strongSelf, key, object);
  243. } withPriority:PINOperationQueuePriorityHigh];
  244. }
  245. - (void)setObjectAsync:(id)object forKey:(NSString *)key completion:(PINCacheObjectBlock)block
  246. {
  247. [self setObjectAsync:object forKey:key withCost:0 completion:block];
  248. }
  249. - (void)setObjectAsync:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost completion:(PINCacheObjectBlock)block
  250. {
  251. __weak PINMemoryCache *weakSelf = self;
  252. [self.operationQueue addOperation:^{
  253. PINMemoryCache *strongSelf = weakSelf;
  254. [strongSelf setObject:object forKey:key withCost:cost];
  255. if (block)
  256. block(strongSelf, key, object);
  257. } withPriority:PINOperationQueuePriorityHigh];
  258. }
  259. - (void)removeObjectForKeyAsync:(NSString *)key completion:(PINCacheObjectBlock)block
  260. {
  261. __weak PINMemoryCache *weakSelf = self;
  262. [self.operationQueue addOperation:^{
  263. PINMemoryCache *strongSelf = weakSelf;
  264. [strongSelf removeObjectForKey:key];
  265. if (block)
  266. block(strongSelf, key, nil);
  267. } withPriority:PINOperationQueuePriorityHigh];
  268. }
  269. - (void)trimToDateAsync:(NSDate *)trimDate completion:(PINCacheBlock)block
  270. {
  271. __weak PINMemoryCache *weakSelf = self;
  272. [self.operationQueue addOperation:^{
  273. PINMemoryCache *strongSelf = weakSelf;
  274. [strongSelf trimToDate:trimDate];
  275. if (block)
  276. block(strongSelf);
  277. } withPriority:PINOperationQueuePriorityHigh];
  278. }
  279. - (void)trimToCostAsync:(NSUInteger)cost completion:(PINCacheBlock)block
  280. {
  281. __weak PINMemoryCache *weakSelf = self;
  282. [self.operationQueue addOperation:^{
  283. PINMemoryCache *strongSelf = weakSelf;
  284. [strongSelf trimToCost:cost];
  285. if (block)
  286. block(strongSelf);
  287. } withPriority:PINOperationQueuePriorityHigh];
  288. }
  289. - (void)trimToCostByDateAsync:(NSUInteger)cost completion:(PINCacheBlock)block
  290. {
  291. __weak PINMemoryCache *weakSelf = self;
  292. [self.operationQueue addOperation:^{
  293. PINMemoryCache *strongSelf = weakSelf;
  294. [strongSelf trimToCostByDate:cost];
  295. if (block)
  296. block(strongSelf);
  297. } withPriority:PINOperationQueuePriorityHigh];
  298. }
  299. - (void)removeAllObjectsAsync:(PINCacheBlock)block
  300. {
  301. __weak PINMemoryCache *weakSelf = self;
  302. [self.operationQueue addOperation:^{
  303. PINMemoryCache *strongSelf = weakSelf;
  304. [strongSelf removeAllObjects];
  305. if (block)
  306. block(strongSelf);
  307. } withPriority:PINOperationQueuePriorityHigh];
  308. }
  309. - (void)enumerateObjectsWithBlockAsync:(PINCacheObjectBlock)block completionBlock:(PINCacheBlock)completionBlock
  310. {
  311. __weak PINMemoryCache *weakSelf = self;
  312. [self.operationQueue addOperation:^{
  313. PINMemoryCache *strongSelf = weakSelf;
  314. [strongSelf enumerateObjectsWithBlock:block];
  315. if (completionBlock)
  316. completionBlock(strongSelf);
  317. } withPriority:PINOperationQueuePriorityHigh];
  318. }
  319. #pragma mark - Public Synchronous Methods -
  320. - (BOOL)containsObjectForKey:(NSString *)key
  321. {
  322. if (!key)
  323. return NO;
  324. [self lock];
  325. BOOL containsObject = (_dictionary[key] != nil);
  326. [self unlock];
  327. return containsObject;
  328. }
  329. - (nullable id)objectForKey:(NSString *)key
  330. {
  331. if (!key)
  332. return nil;
  333. NSDate *now = [[NSDate alloc] init];
  334. [self lock];
  335. id object = nil;
  336. // If the cache should behave like a TTL cache, then only fetch the object if there's a valid ageLimit and the object is still alive
  337. if (!self->_ttlCache || self->_ageLimit <= 0 || fabs([[_dates objectForKey:key] timeIntervalSinceDate:now]) < self->_ageLimit) {
  338. object = _dictionary[key];
  339. }
  340. [self unlock];
  341. if (object) {
  342. [self lock];
  343. _dates[key] = now;
  344. [self unlock];
  345. }
  346. return object;
  347. }
  348. - (id)objectForKeyedSubscript:(NSString *)key
  349. {
  350. return [self objectForKey:key];
  351. }
  352. - (void)setObject:(id)object forKey:(NSString *)key
  353. {
  354. [self setObject:object forKey:key withCost:0];
  355. }
  356. - (void)setObject:(id)object forKeyedSubscript:(NSString *)key
  357. {
  358. if (object == nil) {
  359. [self removeObjectForKey:key];
  360. } else {
  361. [self setObject:object forKey:key];
  362. }
  363. }
  364. - (void)setObject:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost
  365. {
  366. if (!key || !object)
  367. return;
  368. [self lock];
  369. PINCacheObjectBlock willAddObjectBlock = _willAddObjectBlock;
  370. PINCacheObjectBlock didAddObjectBlock = _didAddObjectBlock;
  371. NSUInteger costLimit = _costLimit;
  372. [self unlock];
  373. if (willAddObjectBlock)
  374. willAddObjectBlock(self, key, object);
  375. [self lock];
  376. NSNumber* oldCost = _costs[key];
  377. if (oldCost)
  378. _totalCost -= [oldCost unsignedIntegerValue];
  379. _dictionary[key] = object;
  380. _dates[key] = [[NSDate alloc] init];
  381. _costs[key] = @(cost);
  382. _totalCost += cost;
  383. [self unlock];
  384. if (didAddObjectBlock)
  385. didAddObjectBlock(self, key, object);
  386. if (costLimit > 0)
  387. [self trimToCostByDate:costLimit];
  388. }
  389. - (void)removeObjectForKey:(NSString *)key
  390. {
  391. if (!key)
  392. return;
  393. [self removeObjectAndExecuteBlocksForKey:key];
  394. }
  395. - (void)trimToDate:(NSDate *)trimDate
  396. {
  397. if (!trimDate)
  398. return;
  399. if ([trimDate isEqualToDate:[NSDate distantPast]]) {
  400. [self removeAllObjects];
  401. return;
  402. }
  403. [self trimMemoryToDate:trimDate];
  404. }
  405. - (void)trimToCost:(NSUInteger)cost
  406. {
  407. [self trimToCostLimit:cost];
  408. }
  409. - (void)trimToCostByDate:(NSUInteger)cost
  410. {
  411. [self trimToCostLimitByDate:cost];
  412. }
  413. - (void)removeAllObjects
  414. {
  415. [self lock];
  416. PINCacheBlock willRemoveAllObjectsBlock = _willRemoveAllObjectsBlock;
  417. PINCacheBlock didRemoveAllObjectsBlock = _didRemoveAllObjectsBlock;
  418. [self unlock];
  419. if (willRemoveAllObjectsBlock)
  420. willRemoveAllObjectsBlock(self);
  421. [self lock];
  422. [_dictionary removeAllObjects];
  423. [_dates removeAllObjects];
  424. [_costs removeAllObjects];
  425. _totalCost = 0;
  426. [self unlock];
  427. if (didRemoveAllObjectsBlock)
  428. didRemoveAllObjectsBlock(self);
  429. }
  430. - (void)enumerateObjectsWithBlock:(PINCacheObjectBlock)block
  431. {
  432. if (!block)
  433. return;
  434. [self lock];
  435. NSDate *now = [[NSDate alloc] init];
  436. NSArray *keysSortedByDate = [_dates keysSortedByValueUsingSelector:@selector(compare:)];
  437. for (NSString *key in keysSortedByDate) {
  438. // If the cache should behave like a TTL cache, then only fetch the object if there's a valid ageLimit and the object is still alive
  439. if (!self->_ttlCache || self->_ageLimit <= 0 || fabs([[_dates objectForKey:key] timeIntervalSinceDate:now]) < self->_ageLimit) {
  440. block(self, key, _dictionary[key]);
  441. }
  442. }
  443. [self unlock];
  444. }
  445. #pragma mark - Public Thread Safe Accessors -
  446. - (PINCacheObjectBlock)willAddObjectBlock
  447. {
  448. [self lock];
  449. PINCacheObjectBlock block = _willAddObjectBlock;
  450. [self unlock];
  451. return block;
  452. }
  453. - (void)setWillAddObjectBlock:(PINCacheObjectBlock)block
  454. {
  455. [self lock];
  456. _willAddObjectBlock = [block copy];
  457. [self unlock];
  458. }
  459. - (PINCacheObjectBlock)willRemoveObjectBlock
  460. {
  461. [self lock];
  462. PINCacheObjectBlock block = _willRemoveObjectBlock;
  463. [self unlock];
  464. return block;
  465. }
  466. - (void)setWillRemoveObjectBlock:(PINCacheObjectBlock)block
  467. {
  468. [self lock];
  469. _willRemoveObjectBlock = [block copy];
  470. [self unlock];
  471. }
  472. - (PINCacheBlock)willRemoveAllObjectsBlock
  473. {
  474. [self lock];
  475. PINCacheBlock block = _willRemoveAllObjectsBlock;
  476. [self unlock];
  477. return block;
  478. }
  479. - (void)setWillRemoveAllObjectsBlock:(PINCacheBlock)block
  480. {
  481. [self lock];
  482. _willRemoveAllObjectsBlock = [block copy];
  483. [self unlock];
  484. }
  485. - (PINCacheObjectBlock)didAddObjectBlock
  486. {
  487. [self lock];
  488. PINCacheObjectBlock block = _didAddObjectBlock;
  489. [self unlock];
  490. return block;
  491. }
  492. - (void)setDidAddObjectBlock:(PINCacheObjectBlock)block
  493. {
  494. [self lock];
  495. _didAddObjectBlock = [block copy];
  496. [self unlock];
  497. }
  498. - (PINCacheObjectBlock)didRemoveObjectBlock
  499. {
  500. [self lock];
  501. PINCacheObjectBlock block = _didRemoveObjectBlock;
  502. [self unlock];
  503. return block;
  504. }
  505. - (void)setDidRemoveObjectBlock:(PINCacheObjectBlock)block
  506. {
  507. [self lock];
  508. _didRemoveObjectBlock = [block copy];
  509. [self unlock];
  510. }
  511. - (PINCacheBlock)didRemoveAllObjectsBlock
  512. {
  513. [self lock];
  514. PINCacheBlock block = _didRemoveAllObjectsBlock;
  515. [self unlock];
  516. return block;
  517. }
  518. - (void)setDidRemoveAllObjectsBlock:(PINCacheBlock)block
  519. {
  520. [self lock];
  521. _didRemoveAllObjectsBlock = [block copy];
  522. [self unlock];
  523. }
  524. - (PINCacheBlock)didReceiveMemoryWarningBlock
  525. {
  526. [self lock];
  527. PINCacheBlock block = _didReceiveMemoryWarningBlock;
  528. [self unlock];
  529. return block;
  530. }
  531. - (void)setDidReceiveMemoryWarningBlock:(PINCacheBlock)block
  532. {
  533. [self lock];
  534. _didReceiveMemoryWarningBlock = [block copy];
  535. [self unlock];
  536. }
  537. - (PINCacheBlock)didEnterBackgroundBlock
  538. {
  539. [self lock];
  540. PINCacheBlock block = _didEnterBackgroundBlock;
  541. [self unlock];
  542. return block;
  543. }
  544. - (void)setDidEnterBackgroundBlock:(PINCacheBlock)block
  545. {
  546. [self lock];
  547. _didEnterBackgroundBlock = [block copy];
  548. [self unlock];
  549. }
  550. - (NSTimeInterval)ageLimit
  551. {
  552. [self lock];
  553. NSTimeInterval ageLimit = _ageLimit;
  554. [self unlock];
  555. return ageLimit;
  556. }
  557. - (void)setAgeLimit:(NSTimeInterval)ageLimit
  558. {
  559. [self lock];
  560. _ageLimit = ageLimit;
  561. [self unlock];
  562. [self trimToAgeLimitRecursively];
  563. }
  564. - (NSUInteger)costLimit
  565. {
  566. [self lock];
  567. NSUInteger costLimit = _costLimit;
  568. [self unlock];
  569. return costLimit;
  570. }
  571. - (void)setCostLimit:(NSUInteger)costLimit
  572. {
  573. [self lock];
  574. _costLimit = costLimit;
  575. [self unlock];
  576. if (costLimit > 0)
  577. [self trimToCostLimitByDate:costLimit];
  578. }
  579. - (NSUInteger)totalCost
  580. {
  581. [self lock];
  582. NSUInteger cost = _totalCost;
  583. [self unlock];
  584. return cost;
  585. }
  586. - (BOOL)isTTLCache {
  587. BOOL isTTLCache;
  588. [self lock];
  589. isTTLCache = _ttlCache;
  590. [self unlock];
  591. return isTTLCache;
  592. }
  593. - (void)setTtlCache:(BOOL)ttlCache {
  594. [self lock];
  595. _ttlCache = ttlCache;
  596. [self unlock];
  597. }
  598. - (void)lock
  599. {
  600. __unused int result = pthread_mutex_lock(&_mutex);
  601. NSAssert(result == 0, @"Failed to lock PINMemoryCache %@. Code: %d", self, result);
  602. }
  603. - (void)unlock
  604. {
  605. __unused int result = pthread_mutex_unlock(&_mutex);
  606. NSAssert(result == 0, @"Failed to unlock PINMemoryCache %@. Code: %d", self, result);
  607. }
  608. @end
  609. #pragma mark - Deprecated
  610. @implementation PINMemoryCache (Deprecated)
  611. - (void)containsObjectForKey:(NSString *)key block:(PINMemoryCacheContainmentBlock)block
  612. {
  613. [self containsObjectForKeyAsync:key completion:block];
  614. }
  615. - (void)objectForKey:(NSString *)key block:(nullable PINMemoryCacheObjectBlock)block
  616. {
  617. [self objectForKeyAsync:key completion:block];
  618. }
  619. - (void)setObject:(id)object forKey:(NSString *)key block:(nullable PINMemoryCacheObjectBlock)block
  620. {
  621. [self setObjectAsync:object forKey:key completion:block];
  622. }
  623. - (void)setObject:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost block:(nullable PINMemoryCacheObjectBlock)block
  624. {
  625. [self setObjectAsync:object forKey:key withCost:cost completion:block];
  626. }
  627. - (void)removeObjectForKey:(NSString *)key block:(nullable PINMemoryCacheObjectBlock)block
  628. {
  629. [self removeObjectForKeyAsync:key completion:block];
  630. }
  631. - (void)trimToDate:(NSDate *)date block:(nullable PINMemoryCacheBlock)block
  632. {
  633. [self trimToDateAsync:date completion:block];
  634. }
  635. - (void)trimToCost:(NSUInteger)cost block:(nullable PINMemoryCacheBlock)block
  636. {
  637. [self trimToCostAsync:cost completion:block];
  638. }
  639. - (void)trimToCostByDate:(NSUInteger)cost block:(nullable PINMemoryCacheBlock)block
  640. {
  641. [self trimToCostByDateAsync:cost completion:block];
  642. }
  643. - (void)removeAllObjects:(nullable PINMemoryCacheBlock)block
  644. {
  645. [self removeAllObjectsAsync:block];
  646. }
  647. - (void)enumerateObjectsWithBlock:(PINMemoryCacheObjectBlock)block completionBlock:(nullable PINMemoryCacheBlock)completionBlock
  648. {
  649. [self enumerateObjectsWithBlockAsync:block completionBlock:completionBlock];
  650. }
  651. @end