mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-08-05 16:58:59 +00:00
870 lines
22 KiB
Objective-C
Executable file
870 lines
22 KiB
Objective-C
Executable file
#import "TMMemoryCache.h"
|
|
|
|
NSString * const TMMemoryCachePrefix = @"com.tumblr.TMMemoryCache";
|
|
|
|
@interface TMMemoryCache ()
|
|
#if OS_OBJECT_USE_OBJC
|
|
@property (strong, nonatomic) dispatch_queue_t queue;
|
|
#else
|
|
@property (assign, nonatomic) dispatch_queue_t queue;
|
|
#endif
|
|
@property (strong, nonatomic) NSMutableDictionary *dictionary;
|
|
@property (strong, nonatomic) NSMutableDictionary *dates;
|
|
@property (strong, nonatomic) NSMutableDictionary *costs;
|
|
@end
|
|
|
|
@implementation TMMemoryCache
|
|
|
|
@synthesize ageLimit = _ageLimit;
|
|
@synthesize costLimit = _costLimit;
|
|
@synthesize totalCost = _totalCost;
|
|
@synthesize willAddObjectBlock = _willAddObjectBlock;
|
|
@synthesize willRemoveObjectBlock = _willRemoveObjectBlock;
|
|
@synthesize willRemoveAllObjectsBlock = _willRemoveAllObjectsBlock;
|
|
@synthesize didAddObjectBlock = _didAddObjectBlock;
|
|
@synthesize didRemoveObjectBlock = _didRemoveObjectBlock;
|
|
@synthesize didRemoveAllObjectsBlock = _didRemoveAllObjectsBlock;
|
|
@synthesize didReceiveMemoryWarningBlock = _didReceiveMemoryWarningBlock;
|
|
@synthesize didEnterBackgroundBlock = _didEnterBackgroundBlock;
|
|
|
|
#pragma mark - Initialization -
|
|
|
|
- (void)dealloc
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
|
#if !OS_OBJECT_USE_OBJC
|
|
dispatch_release(_queue);
|
|
_queue = nil;
|
|
#endif
|
|
}
|
|
|
|
- (id)init
|
|
{
|
|
if (self = [super init]) {
|
|
NSString *queueName = [[NSString alloc] initWithFormat:@"%@.%p", TMMemoryCachePrefix, self];
|
|
_queue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_CONCURRENT);
|
|
|
|
_dictionary = [[NSMutableDictionary alloc] init];
|
|
_dates = [[NSMutableDictionary alloc] init];
|
|
_costs = [[NSMutableDictionary alloc] init];
|
|
|
|
_willAddObjectBlock = nil;
|
|
_willRemoveObjectBlock = nil;
|
|
_willRemoveAllObjectsBlock = nil;
|
|
|
|
_didAddObjectBlock = nil;
|
|
_didRemoveObjectBlock = nil;
|
|
_didRemoveAllObjectsBlock = nil;
|
|
|
|
_didReceiveMemoryWarningBlock = nil;
|
|
_didEnterBackgroundBlock = nil;
|
|
|
|
_ageLimit = 0.0;
|
|
_costLimit = 0;
|
|
_totalCost = 0;
|
|
|
|
_removeAllObjectsOnMemoryWarning = YES;
|
|
_removeAllObjectsOnEnteringBackground = YES;
|
|
|
|
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
|
|
for (NSString *name in @[UIApplicationDidReceiveMemoryWarningNotification, UIApplicationDidEnterBackgroundNotification]) {
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(didObserveApocalypticNotification:)
|
|
name:name
|
|
object:[UIApplication sharedApplication]];
|
|
}
|
|
#endif
|
|
}
|
|
return self;
|
|
}
|
|
|
|
+ (instancetype)sharedCache
|
|
{
|
|
static id cache;
|
|
static dispatch_once_t predicate;
|
|
|
|
dispatch_once(&predicate, ^{
|
|
cache = [[self alloc] init];
|
|
});
|
|
|
|
return cache;
|
|
}
|
|
|
|
#pragma mark - Private Methods -
|
|
|
|
- (void)didObserveApocalypticNotification:(NSNotification *)notification
|
|
{
|
|
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
|
|
|
|
if ([[notification name] isEqualToString:UIApplicationDidReceiveMemoryWarningNotification]) {
|
|
if (self.removeAllObjectsOnMemoryWarning)
|
|
[self removeAllObjects:nil];
|
|
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
if (strongSelf->_didReceiveMemoryWarningBlock)
|
|
strongSelf->_didReceiveMemoryWarningBlock(strongSelf);
|
|
});
|
|
} else if ([[notification name] isEqualToString:UIApplicationDidEnterBackgroundNotification]) {
|
|
if (self.removeAllObjectsOnEnteringBackground)
|
|
[self removeAllObjects:nil];
|
|
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
if (strongSelf->_didEnterBackgroundBlock)
|
|
strongSelf->_didEnterBackgroundBlock(strongSelf);
|
|
});
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
- (void)removeObjectAndExecuteBlocksForKey:(NSString *)key
|
|
{
|
|
id object = [_dictionary objectForKey:key];
|
|
NSNumber *cost = [_costs objectForKey:key];
|
|
|
|
if (_willRemoveObjectBlock)
|
|
_willRemoveObjectBlock(self, key, object);
|
|
|
|
if (cost)
|
|
_totalCost -= [cost unsignedIntegerValue];
|
|
|
|
[_dictionary removeObjectForKey:key];
|
|
[_dates removeObjectForKey:key];
|
|
[_costs removeObjectForKey:key];
|
|
|
|
if (_didRemoveObjectBlock)
|
|
_didRemoveObjectBlock(self, key, nil);
|
|
}
|
|
|
|
- (void)trimMemoryToDate:(NSDate *)trimDate
|
|
{
|
|
NSArray *keysSortedByDate = [_dates keysSortedByValueUsingSelector:@selector(compare:)];
|
|
|
|
for (NSString *key in keysSortedByDate) { // oldest objects first
|
|
NSDate *accessDate = [_dates objectForKey:key];
|
|
if (!accessDate)
|
|
continue;
|
|
|
|
if ([accessDate compare:trimDate] == NSOrderedAscending) { // older than trim date
|
|
[self removeObjectAndExecuteBlocksForKey:key];
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)trimToCostLimit:(NSUInteger)limit
|
|
{
|
|
if (_totalCost <= limit)
|
|
return;
|
|
|
|
NSArray *keysSortedByCost = [_costs keysSortedByValueUsingSelector:@selector(compare:)];
|
|
|
|
for (NSString *key in [keysSortedByCost reverseObjectEnumerator]) { // costliest objects first
|
|
[self removeObjectAndExecuteBlocksForKey:key];
|
|
|
|
if (_totalCost <= limit)
|
|
break;
|
|
}
|
|
}
|
|
|
|
- (void)trimToCostLimitByDate:(NSUInteger)limit
|
|
{
|
|
if (_totalCost <= limit)
|
|
return;
|
|
|
|
NSArray *keysSortedByDate = [_dates keysSortedByValueUsingSelector:@selector(compare:)];
|
|
|
|
for (NSString *key in keysSortedByDate) { // oldest objects first
|
|
[self removeObjectAndExecuteBlocksForKey:key];
|
|
|
|
if (_totalCost <= limit)
|
|
break;
|
|
}
|
|
}
|
|
|
|
- (void)trimToAgeLimitRecursively
|
|
{
|
|
if (_ageLimit == 0.0)
|
|
return;
|
|
|
|
NSDate *date = [[NSDate alloc] initWithTimeIntervalSinceNow:-_ageLimit];
|
|
[self trimMemoryToDate:date];
|
|
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_ageLimit * NSEC_PER_SEC));
|
|
dispatch_after(time, _queue, ^(void){
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
__weak TMMemoryCache *weakSelf = strongSelf;
|
|
|
|
dispatch_barrier_async(strongSelf->_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
[strongSelf trimToAgeLimitRecursively];
|
|
});
|
|
});
|
|
}
|
|
|
|
#pragma mark - Public Asynchronous Methods -
|
|
|
|
- (void)objectForKey:(NSString *)key block:(TMMemoryCacheObjectBlock)block
|
|
{
|
|
NSDate *now = [[NSDate alloc] init];
|
|
|
|
if (!key || !block)
|
|
return;
|
|
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
id object = [strongSelf->_dictionary objectForKey:key];
|
|
|
|
if (object) {
|
|
__weak TMMemoryCache *weakSelf = strongSelf;
|
|
dispatch_barrier_async(strongSelf->_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (strongSelf)
|
|
[strongSelf->_dates setObject:now forKey:key];
|
|
});
|
|
}
|
|
|
|
block(strongSelf, key, object);
|
|
});
|
|
}
|
|
|
|
- (void)setObject:(id)object forKey:(NSString *)key block:(TMMemoryCacheObjectBlock)block
|
|
{
|
|
[self setObject:object forKey:key withCost:0 block:block];
|
|
}
|
|
|
|
- (void)setObject:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost block:(TMMemoryCacheObjectBlock)block
|
|
{
|
|
NSDate *now = [[NSDate alloc] init];
|
|
|
|
if (!key || !object)
|
|
return;
|
|
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
if (strongSelf->_willAddObjectBlock)
|
|
strongSelf->_willAddObjectBlock(strongSelf, key, object);
|
|
|
|
[strongSelf->_dictionary setObject:object forKey:key];
|
|
[strongSelf->_dates setObject:now forKey:key];
|
|
[strongSelf->_costs setObject:@(cost) forKey:key];
|
|
|
|
_totalCost += cost;
|
|
|
|
if (strongSelf->_didAddObjectBlock)
|
|
strongSelf->_didAddObjectBlock(strongSelf, key, object);
|
|
|
|
if (strongSelf->_costLimit > 0)
|
|
[strongSelf trimToCostByDate:strongSelf->_costLimit block:nil];
|
|
|
|
if (block) {
|
|
__weak TMMemoryCache *weakSelf = strongSelf;
|
|
dispatch_async(strongSelf->_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (strongSelf)
|
|
block(strongSelf, key, object);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
- (void)removeObjectForKey:(NSString *)key block:(TMMemoryCacheObjectBlock)block
|
|
{
|
|
if (!key)
|
|
return;
|
|
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
[strongSelf removeObjectAndExecuteBlocksForKey:key];
|
|
|
|
if (block) {
|
|
__weak TMMemoryCache *weakSelf = strongSelf;
|
|
dispatch_async(strongSelf->_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (strongSelf)
|
|
block(strongSelf, key, nil);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
- (void)trimToDate:(NSDate *)trimDate block:(TMMemoryCacheBlock)block
|
|
{
|
|
if (!trimDate)
|
|
return;
|
|
|
|
if ([trimDate isEqualToDate:[NSDate distantPast]]) {
|
|
[self removeAllObjects:block];
|
|
return;
|
|
}
|
|
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
[strongSelf trimMemoryToDate:trimDate];
|
|
|
|
if (block) {
|
|
__weak TMMemoryCache *weakSelf = strongSelf;
|
|
dispatch_async(strongSelf->_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (strongSelf)
|
|
block(strongSelf);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
- (void)trimToCost:(NSUInteger)cost block:(TMMemoryCacheBlock)block
|
|
{
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
[strongSelf trimToCostLimit:cost];
|
|
|
|
if (block) {
|
|
__weak TMMemoryCache *weakSelf = strongSelf;
|
|
dispatch_async(strongSelf->_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (strongSelf)
|
|
block(strongSelf);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
- (void)trimToCostByDate:(NSUInteger)cost block:(TMMemoryCacheBlock)block
|
|
{
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
[strongSelf trimToCostLimitByDate:cost];
|
|
|
|
if (block) {
|
|
__weak TMMemoryCache *weakSelf = strongSelf;
|
|
dispatch_async(strongSelf->_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (strongSelf)
|
|
block(strongSelf);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
- (void)removeAllObjects:(TMMemoryCacheBlock)block
|
|
{
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
if (strongSelf->_willRemoveAllObjectsBlock)
|
|
strongSelf->_willRemoveAllObjectsBlock(strongSelf);
|
|
|
|
[strongSelf->_dictionary removeAllObjects];
|
|
[strongSelf->_dates removeAllObjects];
|
|
[strongSelf->_costs removeAllObjects];
|
|
|
|
strongSelf->_totalCost = 0;
|
|
|
|
if (strongSelf->_didRemoveAllObjectsBlock)
|
|
strongSelf->_didRemoveAllObjectsBlock(strongSelf);
|
|
|
|
if (block) {
|
|
__weak TMMemoryCache *weakSelf = strongSelf;
|
|
dispatch_async(strongSelf->_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (strongSelf)
|
|
block(strongSelf);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
- (void)enumerateObjectsWithBlock:(TMMemoryCacheObjectBlock)block completionBlock:(TMMemoryCacheBlock)completionBlock
|
|
{
|
|
if (!block)
|
|
return;
|
|
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
NSArray *keysSortedByDate = [strongSelf->_dates keysSortedByValueUsingSelector:@selector(compare:)];
|
|
|
|
for (NSString *key in keysSortedByDate) {
|
|
block(strongSelf, key, [strongSelf->_dictionary objectForKey:key]);
|
|
}
|
|
|
|
if (completionBlock) {
|
|
__weak TMMemoryCache *weakSelf = strongSelf;
|
|
dispatch_async(strongSelf->_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (strongSelf)
|
|
completionBlock(strongSelf);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
#pragma mark - Public Synchronous Methods -
|
|
|
|
- (id)objectForKey:(NSString *)key
|
|
{
|
|
if (!key)
|
|
return nil;
|
|
|
|
__block id objectForKey = nil;
|
|
|
|
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
|
|
[self objectForKey:key block:^(TMMemoryCache *cache, NSString *key, id object) {
|
|
objectForKey = object;
|
|
dispatch_semaphore_signal(semaphore);
|
|
}];
|
|
|
|
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
|
|
#if !OS_OBJECT_USE_OBJC
|
|
dispatch_release(semaphore);
|
|
#endif
|
|
|
|
return objectForKey;
|
|
}
|
|
|
|
- (void)setObject:(id)object forKey:(NSString *)key
|
|
{
|
|
[self setObject:object forKey:key withCost:0];
|
|
}
|
|
|
|
- (void)setObject:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost
|
|
{
|
|
if (!object || !key)
|
|
return;
|
|
|
|
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
|
|
[self setObject:object forKey:key withCost:cost block:^(TMMemoryCache *cache, NSString *key, id object) {
|
|
dispatch_semaphore_signal(semaphore);
|
|
}];
|
|
|
|
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
|
|
#if !OS_OBJECT_USE_OBJC
|
|
dispatch_release(semaphore);
|
|
#endif
|
|
}
|
|
|
|
- (void)removeObjectForKey:(NSString *)key
|
|
{
|
|
if (!key)
|
|
return;
|
|
|
|
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
|
|
[self removeObjectForKey:key block:^(TMMemoryCache *cache, NSString *key, id object) {
|
|
dispatch_semaphore_signal(semaphore);
|
|
}];
|
|
|
|
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
|
|
#if !OS_OBJECT_USE_OBJC
|
|
dispatch_release(semaphore);
|
|
#endif
|
|
}
|
|
|
|
- (void)trimToDate:(NSDate *)date
|
|
{
|
|
if (!date)
|
|
return;
|
|
|
|
if ([date isEqualToDate:[NSDate distantPast]]) {
|
|
[self removeAllObjects];
|
|
return;
|
|
}
|
|
|
|
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
|
|
[self trimToDate:date block:^(TMMemoryCache *cache) {
|
|
dispatch_semaphore_signal(semaphore);
|
|
}];
|
|
|
|
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
|
|
#if !OS_OBJECT_USE_OBJC
|
|
dispatch_release(semaphore);
|
|
#endif
|
|
}
|
|
|
|
- (void)trimToCost:(NSUInteger)cost
|
|
{
|
|
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
|
|
[self trimToCost:cost block:^(TMMemoryCache *cache) {
|
|
dispatch_semaphore_signal(semaphore);
|
|
}];
|
|
|
|
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
|
|
#if !OS_OBJECT_USE_OBJC
|
|
dispatch_release(semaphore);
|
|
#endif
|
|
}
|
|
|
|
- (void)trimToCostByDate:(NSUInteger)cost
|
|
{
|
|
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
|
|
[self trimToCostByDate:cost block:^(TMMemoryCache *cache) {
|
|
dispatch_semaphore_signal(semaphore);
|
|
}];
|
|
|
|
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
|
|
#if !OS_OBJECT_USE_OBJC
|
|
dispatch_release(semaphore);
|
|
#endif
|
|
}
|
|
|
|
- (void)removeAllObjects
|
|
{
|
|
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
|
|
[self removeAllObjects:^(TMMemoryCache *cache) {
|
|
dispatch_semaphore_signal(semaphore);
|
|
}];
|
|
|
|
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
|
|
#if !OS_OBJECT_USE_OBJC
|
|
dispatch_release(semaphore);
|
|
#endif
|
|
}
|
|
|
|
- (void)enumerateObjectsWithBlock:(TMMemoryCacheObjectBlock)block
|
|
{
|
|
if (!block)
|
|
return;
|
|
|
|
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
|
|
[self enumerateObjectsWithBlock:block completionBlock:^(TMMemoryCache *cache) {
|
|
dispatch_semaphore_signal(semaphore);
|
|
}];
|
|
|
|
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
|
|
#if !OS_OBJECT_USE_OBJC
|
|
dispatch_release(semaphore);
|
|
#endif
|
|
}
|
|
|
|
#pragma mark - Public Thread Safe Accessors -
|
|
|
|
- (TMMemoryCacheObjectBlock)willAddObjectBlock
|
|
{
|
|
__block TMMemoryCacheObjectBlock block = nil;
|
|
|
|
dispatch_sync(_queue, ^{
|
|
block = self->_willAddObjectBlock;
|
|
});
|
|
|
|
return block;
|
|
}
|
|
|
|
- (void)setWillAddObjectBlock:(TMMemoryCacheObjectBlock)block
|
|
{
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
strongSelf->_willAddObjectBlock = [block copy];
|
|
});
|
|
}
|
|
|
|
- (TMMemoryCacheObjectBlock)willRemoveObjectBlock
|
|
{
|
|
__block TMMemoryCacheObjectBlock block = nil;
|
|
|
|
dispatch_sync(_queue, ^{
|
|
block = _willRemoveObjectBlock;
|
|
});
|
|
|
|
return block;
|
|
}
|
|
|
|
- (void)setWillRemoveObjectBlock:(TMMemoryCacheObjectBlock)block
|
|
{
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
strongSelf->_willRemoveObjectBlock = [block copy];
|
|
});
|
|
}
|
|
|
|
- (TMMemoryCacheBlock)willRemoveAllObjectsBlock
|
|
{
|
|
__block TMMemoryCacheBlock block = nil;
|
|
|
|
dispatch_sync(_queue, ^{
|
|
block = _willRemoveAllObjectsBlock;
|
|
});
|
|
|
|
return block;
|
|
}
|
|
|
|
- (void)setWillRemoveAllObjectsBlock:(TMMemoryCacheBlock)block
|
|
{
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
strongSelf->_willRemoveAllObjectsBlock = [block copy];
|
|
});
|
|
}
|
|
|
|
- (TMMemoryCacheObjectBlock)didAddObjectBlock
|
|
{
|
|
__block TMMemoryCacheObjectBlock block = nil;
|
|
|
|
dispatch_sync(_queue, ^{
|
|
block = _didAddObjectBlock;
|
|
});
|
|
|
|
return block;
|
|
}
|
|
|
|
- (void)setDidAddObjectBlock:(TMMemoryCacheObjectBlock)block
|
|
{
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
strongSelf->_didAddObjectBlock = [block copy];
|
|
});
|
|
}
|
|
|
|
- (TMMemoryCacheObjectBlock)didRemoveObjectBlock
|
|
{
|
|
__block TMMemoryCacheObjectBlock block = nil;
|
|
|
|
dispatch_sync(_queue, ^{
|
|
block = _didRemoveObjectBlock;
|
|
});
|
|
|
|
return block;
|
|
}
|
|
|
|
- (void)setDidRemoveObjectBlock:(TMMemoryCacheObjectBlock)block
|
|
{
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
strongSelf->_didRemoveObjectBlock = [block copy];
|
|
});
|
|
}
|
|
|
|
- (TMMemoryCacheBlock)didRemoveAllObjectsBlock
|
|
{
|
|
__block TMMemoryCacheBlock block = nil;
|
|
|
|
dispatch_sync(_queue, ^{
|
|
block = _didRemoveAllObjectsBlock;
|
|
});
|
|
|
|
return block;
|
|
}
|
|
|
|
- (void)setDidRemoveAllObjectsBlock:(TMMemoryCacheBlock)block
|
|
{
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
strongSelf->_didRemoveAllObjectsBlock = [block copy];
|
|
});
|
|
}
|
|
|
|
- (TMMemoryCacheBlock)didReceiveMemoryWarningBlock
|
|
{
|
|
__block TMMemoryCacheBlock block = nil;
|
|
|
|
dispatch_sync(_queue, ^{
|
|
block = _didReceiveMemoryWarningBlock;
|
|
});
|
|
|
|
return block;
|
|
}
|
|
|
|
- (void)setDidReceiveMemoryWarningBlock:(TMMemoryCacheBlock)block
|
|
{
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
strongSelf->_didReceiveMemoryWarningBlock = [block copy];
|
|
});
|
|
}
|
|
|
|
- (TMMemoryCacheBlock)didEnterBackgroundBlock
|
|
{
|
|
__block TMMemoryCacheBlock block = nil;
|
|
|
|
dispatch_sync(_queue, ^{
|
|
block = _didEnterBackgroundBlock;
|
|
});
|
|
|
|
return block;
|
|
}
|
|
|
|
- (void)setDidEnterBackgroundBlock:(TMMemoryCacheBlock)block
|
|
{
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
strongSelf->_didEnterBackgroundBlock = [block copy];
|
|
});
|
|
}
|
|
|
|
- (NSTimeInterval)ageLimit
|
|
{
|
|
__block NSTimeInterval ageLimit = 0.0;
|
|
|
|
dispatch_sync(_queue, ^{
|
|
ageLimit = _ageLimit;
|
|
});
|
|
|
|
return ageLimit;
|
|
}
|
|
|
|
- (void)setAgeLimit:(NSTimeInterval)ageLimit
|
|
{
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
strongSelf->_ageLimit = ageLimit;
|
|
|
|
[strongSelf trimToAgeLimitRecursively];
|
|
});
|
|
}
|
|
|
|
- (NSUInteger)costLimit
|
|
{
|
|
__block NSUInteger costLimit = 0;
|
|
|
|
dispatch_sync(_queue, ^{
|
|
costLimit = _costLimit;
|
|
});
|
|
|
|
return costLimit;
|
|
}
|
|
|
|
- (void)setCostLimit:(NSUInteger)costLimit
|
|
{
|
|
__weak TMMemoryCache *weakSelf = self;
|
|
|
|
dispatch_barrier_async(_queue, ^{
|
|
TMMemoryCache *strongSelf = weakSelf;
|
|
if (!strongSelf)
|
|
return;
|
|
|
|
strongSelf->_costLimit = costLimit;
|
|
|
|
if (costLimit > 0)
|
|
[strongSelf trimToCostLimitByDate:costLimit];
|
|
});
|
|
}
|
|
|
|
- (NSUInteger)totalCost
|
|
{
|
|
__block NSUInteger cost = 0;
|
|
|
|
dispatch_sync(_queue, ^{
|
|
cost = _totalCost;
|
|
});
|
|
|
|
return cost;
|
|
}
|
|
|
|
@end
|