PINMemoryCache.m 20 KB

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