NewsBlur-viq/clients/ios/Other Sources/TMCache/TMDiskCache.m

1040 lines
28 KiB
Objective-C
Executable file

#import "TMDiskCache.h"
#define TMDiskCacheError(error) if (error) { NSLog(@"%@ (%d) ERROR: %@", \
[[NSString stringWithUTF8String:__FILE__] lastPathComponent], \
__LINE__, [error localizedDescription]); }
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
#define TMCacheStartBackgroundTask() UIBackgroundTaskIdentifier taskID = UIBackgroundTaskInvalid; \
taskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ \
[[UIApplication sharedApplication] endBackgroundTask:taskID]; }];
#define TMCacheEndBackgroundTask() [[UIApplication sharedApplication] endBackgroundTask:taskID];
#else
#define TMCacheStartBackgroundTask()
#define TMCacheEndBackgroundTask()
#endif
NSString * const TMDiskCachePrefix = @"com.tumblr.TMDiskCache";
NSString * const TMDiskCacheSharedName = @"TMDiskCacheShared";
@interface TMDiskCache ()
@property (assign) NSUInteger byteCount;
@property (strong, nonatomic) NSURL *cacheURL;
@property (assign, nonatomic) dispatch_queue_t queue;
@property (strong, nonatomic) NSMutableDictionary *dates;
@property (strong, nonatomic) NSMutableDictionary *sizes;
@end
@implementation TMDiskCache
@synthesize willAddObjectBlock = _willAddObjectBlock;
@synthesize willRemoveObjectBlock = _willRemoveObjectBlock;
@synthesize willRemoveAllObjectsBlock = _willRemoveAllObjectsBlock;
@synthesize didAddObjectBlock = _didAddObjectBlock;
@synthesize didRemoveObjectBlock = _didRemoveObjectBlock;
@synthesize didRemoveAllObjectsBlock = _didRemoveAllObjectsBlock;
@synthesize byteLimit = _byteLimit;
@synthesize ageLimit = _ageLimit;
#pragma mark - Initialization -
- (instancetype)initWithName:(NSString *)name
{
return [self initWithName:name rootPath:[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]];
}
- (instancetype)initWithName:(NSString *)name rootPath:(NSString *)rootPath
{
if (!name)
return nil;
if (self = [super init]) {
_name = [name copy];
_queue = [TMDiskCache sharedQueue];
_willAddObjectBlock = nil;
_willRemoveObjectBlock = nil;
_willRemoveAllObjectsBlock = nil;
_didAddObjectBlock = nil;
_didRemoveObjectBlock = nil;
_didRemoveAllObjectsBlock = nil;
_byteCount = 0;
_byteLimit = 0;
_ageLimit = 0.0;
_dates = [[NSMutableDictionary alloc] init];
_sizes = [[NSMutableDictionary alloc] init];
NSString *pathComponent = [[NSString alloc] initWithFormat:@"%@.%@", TMDiskCachePrefix, _name];
_cacheURL = [NSURL fileURLWithPathComponents:@[ rootPath, pathComponent ]];
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
[strongSelf createCacheDirectory];
[strongSelf initializeDiskProperties];
});
}
return self;
}
- (NSString *)description
{
return [[NSString alloc] initWithFormat:@"%@.%@.%p", TMDiskCachePrefix, _name, self];
}
+ (instancetype)sharedCache
{
static id cache;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
cache = [[self alloc] initWithName:TMDiskCacheSharedName];
});
return cache;
}
+ (dispatch_queue_t)sharedQueue
{
static dispatch_queue_t queue;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
queue = dispatch_queue_create([TMDiskCachePrefix UTF8String], DISPATCH_QUEUE_SERIAL);
});
return queue;
}
#pragma mark - Private Methods -
- (NSURL *)encodedFileURLForKey:(NSString *)key
{
if (![key length])
return nil;
return [_cacheURL URLByAppendingPathComponent:[self encodedString:key]];
}
- (NSString *)keyForEncodedFileURL:(NSURL *)url
{
NSString *fileName = [url lastPathComponent];
if (!fileName)
return nil;
return [self decodedString:fileName];
}
- (NSString *)encodedString:(NSString *)string
{
if (![string length])
return @"";
CFStringRef static const charsToEscape = CFSTR(".:/");
CFStringRef escapedString = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(__bridge CFStringRef)string,
NULL,
charsToEscape,
kCFStringEncodingUTF8);
return (__bridge_transfer NSString *)escapedString;
}
- (NSString *)decodedString:(NSString *)string
{
if (![string length])
return @"";
CFStringRef unescapedString = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
(__bridge CFStringRef)string,
CFSTR(""),
kCFStringEncodingUTF8);
return (__bridge_transfer NSString *)unescapedString;
}
#pragma mark - Private Trash Methods -
+ (dispatch_queue_t)sharedTrashQueue
{
static dispatch_queue_t trashQueue;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
NSString *queueName = [[NSString alloc] initWithFormat:@"%@.trash", TMDiskCachePrefix];
trashQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(trashQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
});
return trashQueue;
}
+ (NSURL *)sharedTrashURL
{
static NSURL *sharedTrashURL;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
sharedTrashURL = [[[NSURL alloc] initFileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:TMDiskCachePrefix isDirectory:YES];
dispatch_async([self sharedTrashQueue], ^{
if (![[NSFileManager defaultManager] fileExistsAtPath:[sharedTrashURL path]]) {
NSError *error = nil;
[[NSFileManager defaultManager] createDirectoryAtURL:sharedTrashURL
withIntermediateDirectories:YES
attributes:nil
error:&error];
TMDiskCacheError(error);
}
});
});
return sharedTrashURL;
}
+(BOOL)moveItemAtURLToTrash:(NSURL *)itemURL
{
if (![[NSFileManager defaultManager] fileExistsAtPath:[itemURL path]])
return NO;
NSError *error = nil;
NSString *uniqueString = [[NSProcessInfo processInfo] globallyUniqueString];
NSURL *uniqueTrashURL = [[TMDiskCache sharedTrashURL] URLByAppendingPathComponent:uniqueString];
BOOL moved = [[NSFileManager defaultManager] moveItemAtURL:itemURL toURL:uniqueTrashURL error:&error];
TMDiskCacheError(error);
return moved;
}
+ (void)emptyTrash
{
TMCacheStartBackgroundTask();
dispatch_async([self sharedTrashQueue], ^{
NSError *error = nil;
NSArray *trashedItems = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:[self sharedTrashURL]
includingPropertiesForKeys:nil
options:0
error:&error];
TMDiskCacheError(error);
for (NSURL *trashedItemURL in trashedItems) {
NSError *error = nil;
[[NSFileManager defaultManager] removeItemAtURL:trashedItemURL error:&error];
TMDiskCacheError(error);
}
TMCacheEndBackgroundTask();
});
}
#pragma mark - Private Queue Methods -
- (BOOL)createCacheDirectory
{
if ([[NSFileManager defaultManager] fileExistsAtPath:[_cacheURL path]])
return NO;
NSError *error = nil;
BOOL success = [[NSFileManager defaultManager] createDirectoryAtURL:_cacheURL
withIntermediateDirectories:YES
attributes:nil
error:&error];
TMDiskCacheError(error);
return success;
}
- (void)initializeDiskProperties
{
NSUInteger byteCount = 0;
NSArray *keys = @[ NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey ];
NSError *error = nil;
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:_cacheURL
includingPropertiesForKeys:keys
options:NSDirectoryEnumerationSkipsHiddenFiles
error:&error];
TMDiskCacheError(error);
for (NSURL *fileURL in files) {
NSString *key = [self keyForEncodedFileURL:fileURL];
error = nil;
NSDictionary *dictionary = [fileURL resourceValuesForKeys:keys error:&error];
TMDiskCacheError(error);
NSDate *date = [dictionary objectForKey:NSURLContentModificationDateKey];
if (date)
[_dates setObject:date forKey:key];
NSNumber *fileSize = [dictionary objectForKey:NSURLTotalFileAllocatedSizeKey];
if (fileSize) {
[_sizes setObject:fileSize forKey:key];
byteCount += [fileSize unsignedIntegerValue];
}
}
if (byteCount > 0)
self.byteCount = byteCount; // atomic
}
- (BOOL)setFileModificationDate:(NSDate *)date forURL:(NSURL *)fileURL
{
NSError *error = nil;
BOOL success = [[NSFileManager defaultManager] setAttributes:@{ NSFileModificationDate: date }
ofItemAtPath:[fileURL path]
error:&error];
TMDiskCacheError(error);
if (success)
[_dates setObject:date forKey:[self keyForEncodedFileURL:fileURL]];
return success;
}
- (BOOL)removeFileAndExecuteBlocksForKey:(NSString *)key
{
NSURL *fileURL = [self encodedFileURLForKey:key];
if (!fileURL || ![[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]])
return NO;
if (_willRemoveObjectBlock)
_willRemoveObjectBlock(self, key, nil, fileURL);
BOOL trashed = [TMDiskCache moveItemAtURLToTrash:fileURL];
if (!trashed)
return NO;
[TMDiskCache emptyTrash];
NSNumber *byteSize = [_sizes objectForKey:key];
if (byteSize)
self.byteCount = _byteCount - [byteSize unsignedIntegerValue]; // atomic
[_sizes removeObjectForKey:key];
[_dates removeObjectForKey:key];
if (_didRemoveObjectBlock)
_didRemoveObjectBlock(self, key, nil, fileURL);
return YES;
}
- (void)trimDiskToSize:(NSUInteger)trimByteCount
{
if (_byteCount <= trimByteCount)
return;
NSArray *keysSortedBySize = [_sizes keysSortedByValueUsingSelector:@selector(compare:)];
for (NSString *key in [keysSortedBySize reverseObjectEnumerator]) { // largest objects first
[self removeFileAndExecuteBlocksForKey:key];
if (_byteCount <= trimByteCount)
break;
}
}
- (void)trimDiskToSizeByDate:(NSUInteger)trimByteCount
{
if (_byteCount <= trimByteCount)
return;
NSArray *keysSortedByDate = [_dates keysSortedByValueUsingSelector:@selector(compare:)];
for (NSString *key in keysSortedByDate) { // oldest objects first
[self removeFileAndExecuteBlocksForKey:key];
if (_byteCount <= trimByteCount)
break;
}
}
- (void)trimDiskToDate:(NSDate *)trimDate
{
NSArray *keysSortedByDate = [_dates keysSortedByValueUsingSelector:@selector(compare:)];
for (NSString *key in keysSortedByDate) { // oldest files first
NSDate *accessDate = [_dates objectForKey:key];
if (!accessDate)
continue;
if ([accessDate compare:trimDate] == NSOrderedAscending) { // older than trim date
[self removeFileAndExecuteBlocksForKey:key];
} else {
break;
}
}
}
- (void)trimToAgeLimitRecursively
{
if (_ageLimit == 0.0)
return;
NSDate *date = [[NSDate alloc] initWithTimeIntervalSinceNow:-_ageLimit];
[self trimDiskToDate:date];
__weak TMDiskCache *weakSelf = self;
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_ageLimit * NSEC_PER_SEC));
dispatch_after(time, _queue, ^(void) {
TMDiskCache *strongSelf = weakSelf;
[strongSelf trimToAgeLimitRecursively];
});
}
#pragma mark - Public Asynchronous Methods -
- (void)objectForKey:(NSString *)key block:(TMDiskCacheObjectBlock)block
{
NSDate *now = [[NSDate alloc] init];
if (!key || !block)
return;
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf)
return;
NSURL *fileURL = [strongSelf encodedFileURLForKey:key];
id <NSCoding> object = nil;
if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]) {
object = [NSKeyedUnarchiver unarchiveObjectWithFile:[fileURL path]];
[strongSelf setFileModificationDate:now forURL:fileURL];
}
block(strongSelf, key, object, fileURL);
});
}
- (void)fileURLForKey:(NSString *)key block:(TMDiskCacheObjectBlock)block
{
NSDate *now = [[NSDate alloc] init];
if (!key || !block)
return;
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf)
return;
NSURL *fileURL = [strongSelf encodedFileURLForKey:key];
if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]) {
[strongSelf setFileModificationDate:now forURL:fileURL];
} else {
fileURL = nil;
}
block(strongSelf, key, nil, fileURL);
});
}
- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(TMDiskCacheObjectBlock)block
{
NSDate *now = [[NSDate alloc] init];
if (!key || !object)
return;
TMCacheStartBackgroundTask();
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf) {
TMCacheEndBackgroundTask();
return;
}
NSURL *fileURL = [strongSelf encodedFileURLForKey:key];
if (strongSelf->_willAddObjectBlock)
strongSelf->_willAddObjectBlock(strongSelf, key, object, fileURL);
BOOL written = [NSKeyedArchiver archiveRootObject:object toFile:[fileURL path]];
if (written) {
[strongSelf setFileModificationDate:now forURL:fileURL];
NSError *error = nil;
NSDictionary *values = [fileURL resourceValuesForKeys:@[ NSURLTotalFileAllocatedSizeKey ] error:&error];
TMDiskCacheError(error);
NSNumber *diskFileSize = [values objectForKey:NSURLTotalFileAllocatedSizeKey];
if (diskFileSize) {
[strongSelf->_sizes setObject:diskFileSize forKey:key];
strongSelf.byteCount = strongSelf->_byteCount + [diskFileSize unsignedIntegerValue]; // atomic
}
if (strongSelf->_byteLimit > 0 && strongSelf->_byteCount > strongSelf->_byteLimit)
[strongSelf trimToSizeByDate:strongSelf->_byteLimit block:nil];
} else {
fileURL = nil;
}
if (strongSelf->_didAddObjectBlock)
strongSelf->_didAddObjectBlock(strongSelf, key, object, written ? fileURL : nil);
if (block)
block(strongSelf, key, object, fileURL);
TMCacheEndBackgroundTask();
});
}
- (void)removeObjectForKey:(NSString *)key block:(TMDiskCacheObjectBlock)block
{
if (!key)
return;
TMCacheStartBackgroundTask();
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf) {
TMCacheEndBackgroundTask();
return;
}
NSURL *fileURL = [strongSelf encodedFileURLForKey:key];
[strongSelf removeFileAndExecuteBlocksForKey:key];
if (block)
block(strongSelf, key, nil, fileURL);
TMCacheEndBackgroundTask();
});
}
- (void)trimToSize:(NSUInteger)trimByteCount block:(TMDiskCacheBlock)block
{
if (trimByteCount == 0) {
[self removeAllObjects:block];
return;
}
TMCacheStartBackgroundTask();
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf) {
TMCacheEndBackgroundTask();
return;
}
[strongSelf trimDiskToSize:trimByteCount];
if (block)
block(strongSelf);
TMCacheEndBackgroundTask();
});
}
- (void)trimToDate:(NSDate *)trimDate block:(TMDiskCacheBlock)block
{
if (!trimDate)
return;
if ([trimDate isEqualToDate:[NSDate distantPast]]) {
[self removeAllObjects:block];
return;
}
TMCacheStartBackgroundTask();
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf) {
TMCacheEndBackgroundTask();
return;
}
[strongSelf trimDiskToDate:trimDate];
if (block)
block(strongSelf);
TMCacheEndBackgroundTask();
});
}
- (void)trimToSizeByDate:(NSUInteger)trimByteCount block:(TMDiskCacheBlock)block
{
if (trimByteCount == 0) {
[self removeAllObjects:block];
return;
}
TMCacheStartBackgroundTask();
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf) {
TMCacheEndBackgroundTask();
return;
}
[strongSelf trimDiskToSizeByDate:trimByteCount];
if (block)
block(strongSelf);
TMCacheEndBackgroundTask();
});
}
- (void)removeAllObjects:(TMDiskCacheBlock)block
{
TMCacheStartBackgroundTask();
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf) {
TMCacheEndBackgroundTask();
return;
}
if (strongSelf->_willRemoveAllObjectsBlock)
strongSelf->_willRemoveAllObjectsBlock(strongSelf);
[TMDiskCache moveItemAtURLToTrash:strongSelf->_cacheURL];
[TMDiskCache emptyTrash];
[strongSelf createCacheDirectory];
[strongSelf->_dates removeAllObjects];
[strongSelf->_sizes removeAllObjects];
strongSelf.byteCount = 0; // atomic
if (strongSelf->_didRemoveAllObjectsBlock)
strongSelf->_didRemoveAllObjectsBlock(strongSelf);
if (block)
block(strongSelf);
TMCacheEndBackgroundTask();
});
}
- (void)enumerateObjectsWithBlock:(TMDiskCacheObjectBlock)block completionBlock:(TMDiskCacheBlock)completionBlock
{
if (!block)
return;
TMCacheStartBackgroundTask();
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf) {
TMCacheEndBackgroundTask();
return;
}
NSArray *keysSortedByDate = [strongSelf->_dates keysSortedByValueUsingSelector:@selector(compare:)];
for (NSString *key in keysSortedByDate) {
NSURL *fileURL = [strongSelf encodedFileURLForKey:key];
block(strongSelf, key, nil, fileURL);
}
if (completionBlock)
completionBlock(strongSelf);
TMCacheEndBackgroundTask();
});
}
#pragma mark - Public Synchronous Methods -
- (id <NSCoding>)objectForKey:(NSString *)key
{
if (!key)
return nil;
__block id <NSCoding> objectForKey = nil;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[self objectForKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
objectForKey = object;
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
#if !OS_OBJECT_USE_OBJC
dispatch_release(semaphore);
#endif
return objectForKey;
}
- (NSURL *)fileURLForKey:(NSString *)key
{
if (!key)
return nil;
__block NSURL *fileURLForKey = nil;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[self fileURLForKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
fileURLForKey = fileURL;
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
#if !OS_OBJECT_USE_OBJC
dispatch_release(semaphore);
#endif
return fileURLForKey;
}
- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key
{
if (!object || !key)
return;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[self setObject:object forKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
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:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
#if !OS_OBJECT_USE_OBJC
dispatch_release(semaphore);
#endif
}
- (void)trimToSize:(NSUInteger)byteCount
{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[self trimToSize:byteCount block:^(TMDiskCache *cache) {
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:^(TMDiskCache *cache) {
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
#if !OS_OBJECT_USE_OBJC
dispatch_release(semaphore);
#endif
}
- (void)trimToSizeByDate:(NSUInteger)byteCount
{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[self trimToSizeByDate:byteCount block:^(TMDiskCache *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:^(TMDiskCache *cache) {
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
#if !OS_OBJECT_USE_OBJC
dispatch_release(semaphore);
#endif
}
- (void)enumerateObjectsWithBlock:(TMDiskCacheObjectBlock)block
{
if (!block)
return;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[self enumerateObjectsWithBlock:block completionBlock:^(TMDiskCache *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 -
- (TMDiskCacheObjectBlock)willAddObjectBlock
{
__block TMDiskCacheObjectBlock block = nil;
dispatch_sync(_queue, ^{
block = _willAddObjectBlock;
});
return block;
}
- (void)setWillAddObjectBlock:(TMDiskCacheObjectBlock)block
{
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf)
return;
strongSelf->_willAddObjectBlock = [block copy];
});
}
- (TMDiskCacheObjectBlock)willRemoveObjectBlock
{
__block TMDiskCacheObjectBlock block = nil;
dispatch_sync(_queue, ^{
block = _willRemoveObjectBlock;
});
return block;
}
- (void)setWillRemoveObjectBlock:(TMDiskCacheObjectBlock)block
{
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf)
return;
strongSelf->_willRemoveObjectBlock = [block copy];
});
}
- (TMDiskCacheBlock)willRemoveAllObjectsBlock
{
__block TMDiskCacheBlock block = nil;
dispatch_sync(_queue, ^{
block = _willRemoveAllObjectsBlock;
});
return block;
}
- (void)setWillRemoveAllObjectsBlock:(TMDiskCacheBlock)block
{
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf)
return;
strongSelf->_willRemoveAllObjectsBlock = [block copy];
});
}
- (TMDiskCacheObjectBlock)didAddObjectBlock
{
__block TMDiskCacheObjectBlock block = nil;
dispatch_sync(_queue, ^{
block = _didAddObjectBlock;
});
return block;
}
- (void)setDidAddObjectBlock:(TMDiskCacheObjectBlock)block
{
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf)
return;
strongSelf->_didAddObjectBlock = [block copy];
});
}
- (TMDiskCacheObjectBlock)didRemoveObjectBlock
{
__block TMDiskCacheObjectBlock block = nil;
dispatch_sync(_queue, ^{
block = _didRemoveObjectBlock;
});
return block;
}
- (void)setDidRemoveObjectBlock:(TMDiskCacheObjectBlock)block
{
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf)
return;
strongSelf->_didRemoveObjectBlock = [block copy];
});
}
- (TMDiskCacheBlock)didRemoveAllObjectsBlock
{
__block TMDiskCacheBlock block = nil;
dispatch_sync(_queue, ^{
block = _didRemoveAllObjectsBlock;
});
return block;
}
- (void)setDidRemoveAllObjectsBlock:(TMDiskCacheBlock)block
{
__weak TMDiskCache *weakSelf = self;
dispatch_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf)
return;
strongSelf->_didRemoveAllObjectsBlock = [block copy];
});
}
- (NSUInteger)byteLimit
{
__block NSUInteger byteLimit = 0;
dispatch_sync(_queue, ^{
byteLimit = _byteLimit;
});
return byteLimit;
}
- (void)setByteLimit:(NSUInteger)byteLimit
{
__weak TMDiskCache *weakSelf = self;
dispatch_barrier_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf)
return;
strongSelf->_byteLimit = byteLimit;
if (byteLimit > 0)
[strongSelf trimDiskToSizeByDate:byteLimit];
});
}
- (NSTimeInterval)ageLimit
{
__block NSTimeInterval ageLimit = 0.0;
dispatch_sync(_queue, ^{
ageLimit = _ageLimit;
});
return ageLimit;
}
- (void)setAgeLimit:(NSTimeInterval)ageLimit
{
__weak TMDiskCache *weakSelf = self;
dispatch_barrier_async(_queue, ^{
TMDiskCache *strongSelf = weakSelf;
if (!strongSelf)
return;
strongSelf->_ageLimit = ageLimit;
[strongSelf trimToAgeLimitRecursively];
});
}
@end