1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069 |
- #import "AWSTMDiskCache.h"
- #import "AWSTMCacheBackgroundTaskManager.h"
-
- #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
- #import <UIKit/UIKit.h>
- #endif
-
- #define AWSTMDiskCacheError(error) if (error) { NSLog(@"%@ (%d) ERROR: %@", \
- [[NSString stringWithUTF8String:__FILE__] lastPathComponent], \
- __LINE__, [error localizedDescription]); }
-
- static id <AWSTMCacheBackgroundTaskManager> AWSTMCacheBackgroundTaskManager;
-
- NSString * const AWSTMDiskCachePrefix = @"com.tumblr.TMDiskCache";
- NSString * const AWSTMDiskCacheSharedName = @"TMDiskCacheShared";
-
- @interface AWSTMDiskCache ()
- @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 AWSTMDiskCache
-
- @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 = [AWSTMDiskCache 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:@"%@.%@", AWSTMDiskCachePrefix, _name];
- _cacheURL = [NSURL fileURLWithPathComponents:@[ rootPath, pathComponent ]];
-
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- [strongSelf createCacheDirectory];
- [strongSelf initializeDiskProperties];
- });
- }
- return self;
- }
-
- - (NSString *)description
- {
- return [[NSString alloc] initWithFormat:@"%@.%@.%p", AWSTMDiskCachePrefix, _name, self];
- }
-
- + (instancetype)sharedCache
- {
- static id cache;
- static dispatch_once_t predicate;
-
- dispatch_once(&predicate, ^{
- cache = [[self alloc] initWithName:AWSTMDiskCacheSharedName];
- });
-
- return cache;
- }
-
- + (dispatch_queue_t)sharedQueue
- {
- static dispatch_queue_t queue;
- static dispatch_once_t predicate;
-
- dispatch_once(&predicate, ^{
- queue = dispatch_queue_create([AWSTMDiskCachePrefix 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 @"";
-
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- CFStringRef static const charsToEscape = CFSTR(".:/");
- CFStringRef escapedString = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
- (__bridge CFStringRef)string,
- NULL,
- charsToEscape,
- kCFStringEncodingUTF8);
- #pragma clang diagnostic pop
- return (__bridge_transfer NSString *)escapedString;
- }
-
- - (NSString *)decodedString:(NSString *)string
- {
- if (![string length])
- return @"";
-
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- CFStringRef unescapedString = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
- (__bridge CFStringRef)string,
- CFSTR(""),
- kCFStringEncodingUTF8);
- #pragma clang diagnostic pop
- 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", AWSTMDiskCachePrefix];
- 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:AWSTMDiskCachePrefix isDirectory:YES];
-
- if (![[NSFileManager defaultManager] fileExistsAtPath:[sharedTrashURL path]]) {
- NSError *error = nil;
- [[NSFileManager defaultManager] createDirectoryAtURL:sharedTrashURL
- withIntermediateDirectories:YES
- attributes:nil
- error:&error];
- AWSTMDiskCacheError(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 = [[AWSTMDiskCache sharedTrashURL] URLByAppendingPathComponent:uniqueString];
- BOOL moved = [[NSFileManager defaultManager] moveItemAtURL:itemURL toURL:uniqueTrashURL error:&error];
- AWSTMDiskCacheError(error);
- return moved;
- }
-
- + (void)emptyTrash
- {
- UIBackgroundTaskIdentifier taskID = [AWSTMCacheBackgroundTaskManager beginBackgroundTask];
-
- dispatch_async([self sharedTrashQueue], ^{
- NSError *error = nil;
- NSArray *trashedItems = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:[self sharedTrashURL]
- includingPropertiesForKeys:nil
- options:0
- error:&error];
- AWSTMDiskCacheError(error);
-
- for (NSURL *trashedItemURL in trashedItems) {
- NSError *error = nil;
- [[NSFileManager defaultManager] removeItemAtURL:trashedItemURL error:&error];
- AWSTMDiskCacheError(error);
- }
-
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- });
- }
-
- #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];
- AWSTMDiskCacheError(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];
- AWSTMDiskCacheError(error);
-
- for (NSURL *fileURL in files) {
- NSString *key = [self keyForEncodedFileURL:fileURL];
-
- error = nil;
- NSDictionary *dictionary = [fileURL resourceValuesForKeys:keys error:&error];
- AWSTMDiskCacheError(error);
-
- NSDate *date = [dictionary objectForKey:NSURLContentModificationDateKey];
- if (date && key)
- [_dates setObject:date forKey:key];
-
- NSNumber *fileSize = [dictionary objectForKey:NSURLTotalFileAllocatedSizeKey];
- if (fileSize != nil) {
- [_sizes setObject:fileSize forKey:key];
- byteCount += [fileSize unsignedIntegerValue];
- }
- }
-
- if (byteCount > 0)
- self.byteCount = byteCount; // atomic
- }
-
- - (BOOL)setFileModificationDate:(NSDate *)date forURL:(NSURL *)fileURL
- {
- if (!date || !fileURL) {
- return NO;
- }
-
- NSError *error = nil;
- BOOL success = [[NSFileManager defaultManager] setAttributes:@{ NSFileModificationDate: date }
- ofItemAtPath:[fileURL path]
- error:&error];
- AWSTMDiskCacheError(error);
-
- if (success) {
- NSString *key = [self keyForEncodedFileURL:fileURL];
- if (key) {
- [_dates setObject:date forKey:key];
- }
- }
-
- 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 = [AWSTMDiskCache moveItemAtURLToTrash:fileURL];
- if (!trashed)
- return NO;
-
- [AWSTMDiskCache emptyTrash];
-
- NSNumber *byteSize = [_sizes objectForKey:key];
- if (byteSize != nil)
- 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 AWSTMDiskCache *weakSelf = self;
-
- dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_ageLimit * NSEC_PER_SEC));
- dispatch_after(time, _queue, ^(void) {
- AWSTMDiskCache *strongSelf = weakSelf;
- [strongSelf trimToAgeLimitRecursively];
- });
- }
-
- #pragma mark - Public Asynchronous Methods -
-
- - (void)objectForKey:(NSString *)key block:(AWSTMDiskCacheObjectBlock)block
- {
- NSDate *now = [[NSDate alloc] init];
-
- if (!key || !block)
- return;
-
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf)
- return;
-
- NSURL *fileURL = [strongSelf encodedFileURLForKey:key];
- id <NSCoding> object = nil;
-
- if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]) {
- @try {
- object = [NSKeyedUnarchiver unarchiveObjectWithFile:[fileURL path]];
- }
- @catch (NSException *exception) {
- NSError *error = nil;
- [[NSFileManager defaultManager] removeItemAtPath:[fileURL path] error:&error];
- AWSTMDiskCacheError(error);
- }
-
- [strongSelf setFileModificationDate:now forURL:fileURL];
- }
-
- block(strongSelf, key, object, fileURL);
- });
- }
-
- - (void)fileURLForKey:(NSString *)key block:(AWSTMDiskCacheObjectBlock)block
- {
- NSDate *now = [[NSDate alloc] init];
-
- if (!key || !block)
- return;
-
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *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:(AWSTMDiskCacheObjectBlock)block
- {
- NSDate *now = [[NSDate alloc] init];
-
- if (!key || !object)
- return;
-
- UIBackgroundTaskIdentifier taskID = [AWSTMCacheBackgroundTaskManager beginBackgroundTask];
-
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf) {
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- 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];
- AWSTMDiskCacheError(error);
-
- NSNumber *diskFileSize = [values objectForKey:NSURLTotalFileAllocatedSizeKey];
- if (diskFileSize != nil) {
- NSNumber *oldEntry = [strongSelf->_sizes objectForKey:key];
-
- if ([oldEntry isKindOfClass:[NSNumber class]]){
- strongSelf.byteCount = strongSelf->_byteCount - [oldEntry unsignedIntegerValue];
- }
-
- [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);
-
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- });
- }
-
- - (void)removeObjectForKey:(NSString *)key block:(AWSTMDiskCacheObjectBlock)block
- {
- if (!key)
- return;
-
- UIBackgroundTaskIdentifier taskID = [AWSTMCacheBackgroundTaskManager beginBackgroundTask];
-
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf) {
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- return;
- }
-
- NSURL *fileURL = [strongSelf encodedFileURLForKey:key];
- [strongSelf removeFileAndExecuteBlocksForKey:key];
-
- if (block)
- block(strongSelf, key, nil, fileURL);
-
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- });
- }
-
- - (void)trimToSize:(NSUInteger)trimByteCount block:(AWSTMDiskCacheBlock)block
- {
- if (trimByteCount == 0) {
- [self removeAllObjects:block];
- return;
- }
-
- UIBackgroundTaskIdentifier taskID = [AWSTMCacheBackgroundTaskManager beginBackgroundTask];
-
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf) {
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- return;
- }
-
- [strongSelf trimDiskToSize:trimByteCount];
-
- if (block)
- block(strongSelf);
-
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- });
- }
-
- - (void)trimToDate:(NSDate *)trimDate block:(AWSTMDiskCacheBlock)block
- {
- if (!trimDate)
- return;
-
- if ([trimDate isEqualToDate:[NSDate distantPast]]) {
- [self removeAllObjects:block];
- return;
- }
-
- UIBackgroundTaskIdentifier taskID = [AWSTMCacheBackgroundTaskManager beginBackgroundTask];
-
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf) {
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- return;
- }
-
- [strongSelf trimDiskToDate:trimDate];
-
- if (block)
- block(strongSelf);
-
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- });
- }
-
- - (void)trimToSizeByDate:(NSUInteger)trimByteCount block:(AWSTMDiskCacheBlock)block
- {
- if (trimByteCount == 0) {
- [self removeAllObjects:block];
- return;
- }
-
- UIBackgroundTaskIdentifier taskID = [AWSTMCacheBackgroundTaskManager beginBackgroundTask];
-
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf) {
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- return;
- }
-
- [strongSelf trimDiskToSizeByDate:trimByteCount];
-
- if (block)
- block(strongSelf);
-
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- });
- }
-
- - (void)removeAllObjects:(AWSTMDiskCacheBlock)block
- {
- UIBackgroundTaskIdentifier taskID = [AWSTMCacheBackgroundTaskManager beginBackgroundTask];
-
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf) {
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- return;
- }
-
- if (strongSelf->_willRemoveAllObjectsBlock)
- strongSelf->_willRemoveAllObjectsBlock(strongSelf);
-
- [AWSTMDiskCache moveItemAtURLToTrash:strongSelf->_cacheURL];
- [AWSTMDiskCache emptyTrash];
-
- [strongSelf createCacheDirectory];
-
- [strongSelf->_dates removeAllObjects];
- [strongSelf->_sizes removeAllObjects];
- strongSelf.byteCount = 0; // atomic
-
- if (strongSelf->_didRemoveAllObjectsBlock)
- strongSelf->_didRemoveAllObjectsBlock(strongSelf);
-
- if (block)
- block(strongSelf);
-
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- });
- }
-
- - (void)enumerateObjectsWithBlock:(AWSTMDiskCacheObjectBlock)block completionBlock:(AWSTMDiskCacheBlock)completionBlock
- {
- if (!block)
- return;
-
- UIBackgroundTaskIdentifier taskID = [AWSTMCacheBackgroundTaskManager beginBackgroundTask];
-
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf) {
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- 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);
-
- [AWSTMCacheBackgroundTaskManager endBackgroundTask:taskID];
- });
- }
-
- #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:^(AWSTMDiskCache *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:^(AWSTMDiskCache *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:^(AWSTMDiskCache *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:^(AWSTMDiskCache *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:^(AWSTMDiskCache *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:^(AWSTMDiskCache *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:^(AWSTMDiskCache *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:^(AWSTMDiskCache *cache) {
- dispatch_semaphore_signal(semaphore);
- }];
-
- dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-
- #if !OS_OBJECT_USE_OBJC
- dispatch_release(semaphore);
- #endif
- }
-
- - (void)enumerateObjectsWithBlock:(AWSTMDiskCacheObjectBlock)block
- {
- if (!block)
- return;
-
- dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-
- [self enumerateObjectsWithBlock:block completionBlock:^(AWSTMDiskCache *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 -
-
- - (AWSTMDiskCacheObjectBlock)willAddObjectBlock
- {
- __block AWSTMDiskCacheObjectBlock block = nil;
-
- dispatch_sync(_queue, ^{
- block = self->_willAddObjectBlock;
- });
-
- return block;
- }
-
- - (void)setWillAddObjectBlock:(AWSTMDiskCacheObjectBlock)block
- {
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf)
- return;
-
- strongSelf->_willAddObjectBlock = [block copy];
- });
- }
-
- - (AWSTMDiskCacheObjectBlock)willRemoveObjectBlock
- {
- __block AWSTMDiskCacheObjectBlock block = nil;
-
- dispatch_sync(_queue, ^{
- block = self->_willRemoveObjectBlock;
- });
-
- return block;
- }
-
- - (void)setWillRemoveObjectBlock:(AWSTMDiskCacheObjectBlock)block
- {
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf)
- return;
-
- strongSelf->_willRemoveObjectBlock = [block copy];
- });
- }
-
- - (AWSTMDiskCacheBlock)willRemoveAllObjectsBlock
- {
- __block AWSTMDiskCacheBlock block = nil;
-
- dispatch_sync(_queue, ^{
- block = self->_willRemoveAllObjectsBlock;
- });
-
- return block;
- }
-
- - (void)setWillRemoveAllObjectsBlock:(AWSTMDiskCacheBlock)block
- {
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf)
- return;
-
- strongSelf->_willRemoveAllObjectsBlock = [block copy];
- });
- }
-
- - (AWSTMDiskCacheObjectBlock)didAddObjectBlock
- {
- __block AWSTMDiskCacheObjectBlock block = nil;
-
- dispatch_sync(_queue, ^{
- block = self->_didAddObjectBlock;
- });
-
- return block;
- }
-
- - (void)setDidAddObjectBlock:(AWSTMDiskCacheObjectBlock)block
- {
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf)
- return;
-
- strongSelf->_didAddObjectBlock = [block copy];
- });
- }
-
- - (AWSTMDiskCacheObjectBlock)didRemoveObjectBlock
- {
- __block AWSTMDiskCacheObjectBlock block = nil;
-
- dispatch_sync(_queue, ^{
- block = self->_didRemoveObjectBlock;
- });
-
- return block;
- }
-
- - (void)setDidRemoveObjectBlock:(AWSTMDiskCacheObjectBlock)block
- {
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf)
- return;
-
- strongSelf->_didRemoveObjectBlock = [block copy];
- });
- }
-
- - (AWSTMDiskCacheBlock)didRemoveAllObjectsBlock
- {
- __block AWSTMDiskCacheBlock block = nil;
-
- dispatch_sync(_queue, ^{
- block = self->_didRemoveAllObjectsBlock;
- });
-
- return block;
- }
-
- - (void)setDidRemoveAllObjectsBlock:(AWSTMDiskCacheBlock)block
- {
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf)
- return;
-
- strongSelf->_didRemoveAllObjectsBlock = [block copy];
- });
- }
-
- - (NSUInteger)byteLimit
- {
- __block NSUInteger byteLimit = 0;
-
- dispatch_sync(_queue, ^{
- byteLimit = self->_byteLimit;
- });
-
- return byteLimit;
- }
-
- - (void)setByteLimit:(NSUInteger)byteLimit
- {
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_barrier_async(_queue, ^{
- AWSTMDiskCache *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 = self->_ageLimit;
- });
-
- return ageLimit;
- }
-
- - (void)setAgeLimit:(NSTimeInterval)ageLimit
- {
- __weak AWSTMDiskCache *weakSelf = self;
-
- dispatch_barrier_async(_queue, ^{
- AWSTMDiskCache *strongSelf = weakSelf;
- if (!strongSelf)
- return;
-
- strongSelf->_ageLimit = ageLimit;
-
- [strongSelf trimToAgeLimitRecursively];
- });
- }
-
- #pragma mark - Background Tasks -
-
- + (void)setBackgroundTaskManager:(id <AWSTMCacheBackgroundTaskManager>)backgroundTaskManager {
- AWSTMCacheBackgroundTaskManager = backgroundTaskManager;
- }
-
- @end
|