Skip to content

Commit a1cc095

Browse files
author
Daryll Herberger
committed
Merging changes from PR TumblrArchive#30 and PR TumblrArchive#37 from their respective forks
1 parent 7f928da commit a1cc095

File tree

9 files changed

+153
-84
lines changed

9 files changed

+153
-84
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
### 1.3.0 -- 2013 XXXX ###
2+
3+
- [new] TMDiskCache: introduced concept of "trash" for rapid wipeouts
4+
5+
16
### 1.2.0 -- 2013 May 24 ###
27

38
- [new] TMDiskCache: added method `enumerateObjectsWithBlock:completionBlock:`

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
`TMCache` and `TMDiskCache` accept any object conforming to [NSCoding](https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Protocols/NSCoding_Protocol/Reference/Reference.html). Put things in like this:
88

99
```objective-c
10-
UIImage *image = [[UIImage alloc] initWithData:data scale:[[UIScreen mainScreen] scale]];
11-
[[TMCache sharedCache] setObject:image forKey:@"image" block:nil]; // returns immediately
10+
UIImage *img = [[UIImage alloc] initWithData:data scale:[[UIScreen mainScreen] scale]];
11+
[[TMCache sharedCache] setObject:img forKey:@"image" block:nil]; // returns immediately
1212
```
1313
1414
Get them back out like this:
@@ -28,7 +28,7 @@ Collections work too. Thanks to the magic of `NSKeyedArchiver`, objects repeated
2828
```objective-c
2929
NSArray *images = @[ image, image, image ];
3030
[[TMCache sharedCache] setObject:images forKey:@"images"];
31-
NSLog(@"three for the price of one: %d", [[[TMCache sharedCache] diskCache] byteCount]);
31+
NSLog(@"3 for the price of 1: %d", [[[TMCache sharedCache] diskCache] byteCount]);
3232
```
3333
3434
## Installation ##

TMCache/TMCache.m

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ - (void)objectForKey:(NSString *)key readBlock:(TMCacheReadBlock)readBlock block
131131

132132
- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(TMCacheObjectBlock)block
133133
{
134-
return [self setObject:object forKey:key writeBlock:NULL block:block];
134+
[self setObject:object forKey:key writeBlock:NULL block:block];
135135
}
136136

137137
- (void)setObject:(id)object forKey:(NSString *)key writeBlock:(TMCacheWriteBlock)writeBlock block:(TMCacheObjectBlock)block
@@ -329,22 +329,26 @@ - (id)objectForKey:(NSString *)key readBlock:(TMCacheReadBlock)readBlock
329329
if (!key)
330330
return nil;
331331

332-
__block id objectForKey = nil;
333-
334-
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
335-
336-
[self objectForKey:key readBlock:readBlock block:^(TMCache *cache, NSString *key, id object) {
337-
objectForKey = object;
338-
dispatch_semaphore_signal(semaphore);
339-
}];
340-
341-
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
342-
343-
#if !OS_OBJECT_USE_OBJC
344-
dispatch_release(semaphore);
345-
#endif
346-
347-
return objectForKey;
332+
id object = [_memoryCache objectForKey:key];
333+
334+
if (object) {
335+
__weak TMCache *weakSelf = self;
336+
dispatch_barrier_async(_queue, ^{
337+
TMCache *strongSelf = weakSelf;
338+
if (strongSelf)
339+
[strongSelf->_diskCache fileURLForKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
340+
// update the access time on disk
341+
}];
342+
});
343+
} else {
344+
object = [_diskCache objectForKey:key];
345+
346+
if (object) {
347+
[_memoryCache setObject:object forKey:key block:nil];
348+
}
349+
};
350+
351+
return object;
348352
}
349353

350354
- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key
@@ -423,4 +427,4 @@ - (void)removeAllObjects
423427

424428
@end
425429

426-
#pragma HC SVNT DRACONES
430+
// HC SVNT DRACONES

TMCache/TMDiskCache.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ typedef id (^TMDiskCacheReadBlock)(TMDiskCache *cache, NSString *key, NSURL *fil
134134
*/
135135
+ (dispatch_queue_t)sharedQueue;
136136

137+
/**
138+
Empties the trash with `DISPATCH_QUEUE_PRIORITY_BACKGROUND`. Does not block the <sharedQueue>.
139+
*/
140+
+ (void)emptyTrash;
141+
142+
137143
/**
138144
The designated initializer. Multiple instances with the same name are allowed and can safely access
139145
the same data on disk thanks to the magic of seriality.

TMCache/TMDiskCache.m

Lines changed: 97 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,80 @@ - (NSString *)decodedString:(NSString *)string
150150
return (__bridge_transfer NSString *)unescapedString;
151151
}
152152

153+
#pragma mark - Private Trash Methods -
154+
155+
+ (dispatch_queue_t)sharedTrashQueue
156+
{
157+
static dispatch_queue_t trashQueue;
158+
static dispatch_once_t predicate;
159+
160+
dispatch_once(&predicate, ^{
161+
NSString *queueName = [[NSString alloc] initWithFormat:@"%@.trash", TMDiskCachePrefix];
162+
trashQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL);
163+
dispatch_set_target_queue(trashQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
164+
});
165+
166+
return trashQueue;
167+
}
168+
169+
+ (NSURL *)sharedTrashURL
170+
{
171+
static NSURL *sharedTrashURL;
172+
static dispatch_once_t predicate;
173+
174+
dispatch_once(&predicate, ^{
175+
sharedTrashURL = [[[NSURL alloc] initFileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:TMDiskCachePrefix isDirectory:YES];
176+
177+
dispatch_async([self sharedTrashQueue], ^{
178+
if (![[NSFileManager defaultManager] fileExistsAtPath:[sharedTrashURL path]]) {
179+
NSError *error = nil;
180+
[[NSFileManager defaultManager] createDirectoryAtURL:sharedTrashURL
181+
withIntermediateDirectories:YES
182+
attributes:nil
183+
error:&error];
184+
TMDiskCacheError(error);
185+
}
186+
});
187+
});
188+
189+
return sharedTrashURL;
190+
}
191+
192+
+(BOOL)moveItemAtURLToTrash:(NSURL *)itemURL
193+
{
194+
if (![[NSFileManager defaultManager] fileExistsAtPath:[itemURL path]])
195+
return NO;
196+
197+
NSError *error = nil;
198+
NSString *uniqueString = [[NSProcessInfo processInfo] globallyUniqueString];
199+
NSURL *uniqueTrashURL = [[TMDiskCache sharedTrashURL] URLByAppendingPathComponent:uniqueString];
200+
BOOL moved = [[NSFileManager defaultManager] moveItemAtURL:itemURL toURL:uniqueTrashURL error:&error];
201+
TMDiskCacheError(error);
202+
return moved;
203+
}
204+
205+
+ (void)emptyTrash
206+
{
207+
TMCacheStartBackgroundTask();
208+
209+
dispatch_async([self sharedTrashQueue], ^{
210+
NSError *error = nil;
211+
NSArray *trashedItems = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:[self sharedTrashURL]
212+
includingPropertiesForKeys:nil
213+
options:0
214+
error:&error];
215+
TMDiskCacheError(error);
216+
217+
for (NSURL *trashedItemURL in trashedItems) {
218+
NSError *error = nil;
219+
[[NSFileManager defaultManager] removeItemAtURL:trashedItemURL error:&error];
220+
TMDiskCacheError(error);
221+
}
222+
223+
TMCacheEndBackgroundTask();
224+
});
225+
}
226+
153227
#pragma mark - Private Queue Methods -
154228

155229
- (BOOL)createCacheDirectory
@@ -224,12 +298,11 @@ - (BOOL)removeFileAndExecuteBlocksForKey:(NSString *)key
224298
if (_willRemoveObjectBlock)
225299
_willRemoveObjectBlock(self, key, nil, fileURL);
226300

227-
NSError *error = nil;
228-
BOOL removed = [[NSFileManager defaultManager] removeItemAtURL:fileURL error:&error];
229-
TMDiskCacheError(error);
230-
231-
if (!removed)
301+
BOOL trashed = [TMDiskCache moveItemAtURLToTrash:fileURL];
302+
if (!trashed)
232303
return NO;
304+
305+
[TMDiskCache emptyTrash];
233306

234307
NSNumber *byteSize = [_sizes objectForKey:key];
235308
if (byteSize)
@@ -409,7 +482,7 @@ - (void)setObject:(id)object forKey:(NSString *)key writeBlock:(TMDiskCacheWrite
409482
if (written) {
410483
[strongSelf setFileModificationDate:now forURL:fileURL];
411484

412-
error = nil;
485+
NSError *error = nil;
413486
NSDictionary *values = [fileURL resourceValuesForKeys:@[ NSURLTotalFileAllocatedSizeKey ] error:&error];
414487
TMDiskCacheError(error);
415488

@@ -560,12 +633,9 @@ - (void)removeAllObjects:(TMDiskCacheBlock)block
560633

561634
if (strongSelf->_willRemoveAllObjectsBlock)
562635
strongSelf->_willRemoveAllObjectsBlock(strongSelf);
563-
564-
if ([[NSFileManager defaultManager] fileExistsAtPath:[strongSelf->_cacheURL path]]) {
565-
NSError *error = nil;
566-
[[NSFileManager defaultManager] removeItemAtURL:strongSelf->_cacheURL error:&error];
567-
TMDiskCacheError(error);
568-
}
636+
637+
[TMDiskCache moveItemAtURLToTrash:strongSelf->_cacheURL];
638+
[TMDiskCache emptyTrash];
569639

570640
[strongSelf createCacheDirectory];
571641

@@ -624,23 +694,22 @@ - (id)objectForKey:(NSString *)key readBlock:(TMDiskCacheReadBlock)readBlock
624694
{
625695
if (!key)
626696
return nil;
627-
628-
__block id <NSCoding> objectForKey = nil;
629-
630-
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
631-
632-
[self objectForKey:key readBlock:readBlock block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
633-
objectForKey = object;
634-
dispatch_semaphore_signal(semaphore);
635-
}];
636697

637-
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
638-
639-
#if !OS_OBJECT_USE_OBJC
640-
dispatch_release(semaphore);
641-
#endif
642-
643-
return objectForKey;
698+
NSURL *fileURL = [self encodedFileURLForKey:key];
699+
700+
// No need to check if file exists, as unarchiveObjectWithFile returns nil if there is no file at path
701+
id <NSCoding> object = [NSKeyedUnarchiver unarchiveObjectWithFile:[fileURL path]];
702+
703+
if (object) {
704+
__weak TMDiskCache *weakSelf = self;
705+
dispatch_barrier_async(_queue, ^{
706+
TMDiskCache *strongSelf = weakSelf;
707+
if (strongSelf)
708+
[strongSelf setFileModificationDate:[NSDate new] forURL:fileURL];
709+
});
710+
}
711+
712+
return object;
644713
}
645714

646715
- (NSURL *)fileURLForKey:(NSString *)key

TMCache/TMMemoryCache.m

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,6 @@ - (void)trimToAgeLimitRecursively
225225

226226
- (void)objectForKey:(NSString *)key block:(TMMemoryCacheObjectBlock)block
227227
{
228-
NSDate *now = [[NSDate alloc] init];
229-
230228
if (!key || !block)
231229
return;
232230

@@ -237,18 +235,7 @@ - (void)objectForKey:(NSString *)key block:(TMMemoryCacheObjectBlock)block
237235
if (!strongSelf)
238236
return;
239237

240-
id object = [strongSelf->_dictionary objectForKey:key];
241-
242-
if (object) {
243-
__weak TMMemoryCache *weakSelf = strongSelf;
244-
dispatch_barrier_async(strongSelf->_queue, ^{
245-
TMMemoryCache *strongSelf = weakSelf;
246-
if (strongSelf)
247-
[strongSelf->_dates setObject:now forKey:key];
248-
});
249-
}
250-
251-
block(strongSelf, key, object);
238+
block(strongSelf, key, [strongSelf objectForKey:key]);
252239
});
253240
}
254241

@@ -463,23 +450,19 @@ - (id)objectForKey:(NSString *)key
463450
{
464451
if (!key)
465452
return nil;
466-
467-
__block id objectForKey = nil;
468-
469-
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
470-
471-
[self objectForKey:key block:^(TMMemoryCache *cache, NSString *key, id object) {
472-
objectForKey = object;
473-
dispatch_semaphore_signal(semaphore);
474-
}];
475-
476-
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
477-
478-
#if !OS_OBJECT_USE_OBJC
479-
dispatch_release(semaphore);
480-
#endif
481-
482-
return objectForKey;
453+
454+
id object = [_dictionary objectForKey:key];
455+
456+
if (object) {
457+
__weak TMMemoryCache *weakSelf = self;
458+
dispatch_barrier_async(_queue, ^{
459+
TMMemoryCache *strongSelf = weakSelf;
460+
if (strongSelf)
461+
[strongSelf->_dates setObject:[NSDate new] forKey:key];
462+
});
463+
}
464+
465+
return object;
483466
}
484467

485468
- (void)setObject:(id)object forKey:(NSString *)key

build_tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/usr/bin/env sh
22

3-
xcodebuild -project tests/TMCache.xcodeproj -scheme TMCacheTests -sdk iphonesimulator TEST_AFTER_BUILD=YES clean build
3+
xcodebuild ONLY_ACTIVE_ARCH=NO -project tests/TMCache.xcodeproj -scheme TMCacheTests -sdk iphonesimulator TEST_AFTER_BUILD=YES clean build

tests/TMCache.xcodeproj/project.pbxproj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@
211211
isa = PBXProject;
212212
attributes = {
213213
CLASSPREFIX = TM;
214-
LastUpgradeCheck = 0460;
214+
LastUpgradeCheck = 0500;
215215
ORGANIZATIONNAME = Tumblr;
216216
};
217217
buildConfigurationList = D07F1EAD171AFB7A001DBA02 /* Build configuration list for PBXProject "TMCache" */;
@@ -329,7 +329,7 @@
329329
GCC_WARN_UNINITIALIZED_AUTOS = YES;
330330
GCC_WARN_UNUSED_VARIABLE = YES;
331331
IPHONEOS_DEPLOYMENT_TARGET = 6.1;
332-
ONLY_ACTIVE_ARCH = NO;
332+
ONLY_ACTIVE_ARCH = YES;
333333
SDKROOT = iphoneos;
334334
TARGETED_DEVICE_FAMILY = "1,2";
335335
};
@@ -402,6 +402,7 @@
402402
INFOPLIST_FILE = "TMCacheTests/TMCacheTests-Info.plist";
403403
PRODUCT_NAME = "$(TARGET_NAME)";
404404
TEST_HOST = "$(BUNDLE_LOADER)";
405+
VALID_ARCHS = "arm64 armv7 armv7s i386 x86_64";
405406
WRAPPER_EXTENSION = octest;
406407
};
407408
name = Debug;
@@ -419,6 +420,7 @@
419420
INFOPLIST_FILE = "TMCacheTests/TMCacheTests-Info.plist";
420421
PRODUCT_NAME = "$(TARGET_NAME)";
421422
TEST_HOST = "$(BUNDLE_LOADER)";
423+
VALID_ARCHS = "arm64 armv7 armv7s i386 x86_64";
422424
WRAPPER_EXTENSION = octest;
423425
};
424426
name = Release;

tests/TMCache.xcodeproj/xcshareddata/xcschemes/TMCacheTests.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "0460"
3+
LastUpgradeVersion = "0500"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"

0 commit comments

Comments
 (0)