├── Classes ├── TSFileCache.h ├── TSFileCache.m ├── TSImageCache.h └── TSImageCache.m ├── Example ├── TSImageCache.h ├── TSImageCache.m └── image.png ├── LICENSE ├── README.md ├── TSFileCache.podspec ├── TSFileCache.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── tomkowz_priv.xcuserdatad │ └── xcschemes │ ├── TSFileCache.xcscheme │ └── xcschememanagement.plist ├── TSFileCache ├── TSAppDelegate.h ├── TSAppDelegate.m ├── TSFileCache-Info.plist ├── TSFileCache-Prefix.pch ├── en.lproj │ └── InfoPlist.strings └── main.m └── TSFileCacheTests ├── TSFileCacheTests-Info.plist ├── TSFileCacheTests.m └── en.lproj └── InfoPlist.strings /Classes/TSFileCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // TSFileCache.h 3 | // TSFileCache 4 | // 5 | // Created by Tomasz Szulc on 15/04/14. 6 | // Copyright (c) 2014 Tomasz Szulc. All rights reserved. 7 | // http://github.com/tomkowz/TSFileCache 8 | // 9 | 10 | #import 11 | 12 | /** 13 | If you want to prevent your subclass to use one of methods below apply this macro. 14 | + (void)setSharedInstance:(TSFileCache *)instance __TSFileCacheUnavailable__; 15 | */ 16 | #ifndef __TSFileCacheUnavailable__ 17 | #define __TSFileCacheUnavailable__ __attribute__((unavailable("Method is not available in this subclass."))) 18 | #endif 19 | 20 | @interface TSFileCache : NSObject 21 | 22 | @property (nonatomic, readonly) NSURL *directoryURL; 23 | @property (nonatomic, readonly) NSCache *cache; 24 | 25 | /// Set shared instance. 26 | + (void)setSharedInstance:(TSFileCache *)instance; 27 | 28 | /// Get shared instance. Nil if not set. 29 | + (instancetype)sharedInstance; 30 | 31 | 32 | 33 | /// Instance which has set directoryURL. Method does not create directory. 34 | + (instancetype)cacheForURL:(NSURL *)directoryURL; 35 | 36 | /// Instance which has set directoryURL relative to NSTemporaryDirectory(). Method does not create relative directory. 37 | + (instancetype)cacheInTemporaryDirectoryWithRelativeURL:(NSURL *)relativeURL; 38 | 39 | 40 | 41 | /// Prepare instance to work. Call after init. 42 | - (BOOL)prepare:(NSError **)error; 43 | 44 | /// Clear container if exists - directory will still exists 45 | - (void)clear; 46 | 47 | 48 | /// Returns data for key. Nil if key is not set 49 | - (NSData *)dataForKey:(NSString *)key; 50 | 51 | /// Store data for passed key. 52 | - (void)writeDataOnDisk:(NSData *)data forKey:(NSString *)key; 53 | 54 | /// Store data for undefined key. Returns key. Key is unique. 55 | - (NSString *)storeDataForUndefinedKey:(NSData *)data; 56 | 57 | /// Removes data for specified key 58 | - (void)removeDataForKey:(NSString *)key; 59 | 60 | /// Check if data exists for key. 61 | - (BOOL)existsDataForKey:(NSString *)key; 62 | 63 | /// Returns all set keys. 64 | - (NSArray *)allKeys; 65 | 66 | /// If file exists attributes will be returned. Otherwise empty dictionary. 67 | - (NSDictionary *)attributesOfFileForKey:(NSString *)key error:(NSError **)error; 68 | 69 | @end 70 | 71 | 72 | /// object[@"key"] = ...;, NSData *value = object[@"key"]; 73 | @interface TSFileCache (Subscript) 74 | - (NSData *)objectForKeyedSubscript:(NSString *)key; 75 | - (void)setObject:(NSData *)data forKeyedSubscript:(NSString *)key; 76 | @end 77 | 78 | -------------------------------------------------------------------------------- /Classes/TSFileCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // TSFileCache.m 3 | // TSFileCache 4 | // 5 | // Created by Tomasz Szulc on 15/04/14. 6 | // Copyright (c) 2014 Tomasz Szulc. All rights reserved. 7 | // 8 | 9 | #import "TSFileCache.h" 10 | 11 | #define URLTo(url) [_directoryURL URLByAppendingPathComponent:url] 12 | 13 | @interface NSURL (TSFileCache) 14 | - (NSURL *)_tsfc_appendURL:(NSURL *)url; 15 | @end 16 | 17 | static NSString * const TSFileCacheErrorDomain = @"TSFileCacheErrorDomain"; 18 | @interface NSError (TSFileCache) 19 | + (NSError *)_tsfc_errorWithDescription:(NSString *)description; 20 | @end 21 | 22 | 23 | @interface TSFileCache (Prepare) 24 | - (BOOL)_prepareWithDirectoryAtURL:(NSURL *)directoryURL error:(NSError **)error; 25 | @end 26 | 27 | @interface TSFileCache (StorageManager) 28 | - (BOOL)_existsFileAtURL:(NSURL *)fileURL; 29 | - (NSData *)_readFileAtURL:(NSURL *)fileURL; 30 | - (void)_writeData:(NSData *)data atURL:(NSURL *)fileURL; 31 | - (void)_removeDataAtURL:(NSURL *)fileURL; 32 | - (void)_clearDirectoryAtURL:(NSURL *)storageURL; 33 | - (NSArray *)_allFileNamesAtURL:(NSURL *)directoryURL; 34 | - (NSDictionary *)_attributesOfFileAtURL:(NSURL *)fileURL error:(NSError **)error; 35 | @end 36 | 37 | 38 | @implementation TSFileCache { 39 | NSCache *_cache; 40 | } 41 | 42 | static TSFileCache *_sharedInstance = nil; 43 | + (void)setSharedInstance:(TSFileCache *)instance { 44 | _sharedInstance = instance; 45 | } 46 | 47 | + (instancetype)sharedInstance { 48 | return _sharedInstance; 49 | } 50 | 51 | #pragma mark - Initializers 52 | + (instancetype)cacheForURL:(NSURL *)directoryURL { 53 | NSParameterAssert(directoryURL && [directoryURL isFileURL]); 54 | return [[self alloc] _initWithDirectoryURL:directoryURL]; 55 | } 56 | 57 | + (instancetype)cacheInTemporaryDirectoryWithRelativeURL:(NSURL *)relativeURL { 58 | NSParameterAssert(relativeURL); 59 | /// Build url relative to temporary directory 60 | NSURL *directoryURL = [[self _temporaryDirectoryURL] _tsfc_appendURL:relativeURL]; 61 | return [self cacheForURL:directoryURL]; 62 | } 63 | 64 | 65 | #pragma mark - Initialization 66 | - (instancetype)_initWithDirectoryURL:(NSURL *)directoryURL { 67 | self = [super init]; 68 | if (self) { 69 | _directoryURL = directoryURL; 70 | _cache = [[NSCache alloc] init]; 71 | } 72 | return self; 73 | } 74 | 75 | 76 | #pragma mark - Externals 77 | - (BOOL)prepare:(NSError *__autoreleasing *)error { 78 | NSError *localError = nil; 79 | BOOL success = [self _prepareWithDirectoryAtURL:_directoryURL error:&localError]; 80 | /// log error if occured 81 | if (localError && error) { 82 | *error = localError; 83 | } 84 | return success; 85 | } 86 | 87 | - (void)clear { 88 | [_cache removeAllObjects]; 89 | [self _clearDirectoryAtURL:_directoryURL]; 90 | } 91 | 92 | - (NSData *)dataForKey:(NSString *)key { 93 | NSData *data = nil; 94 | if (key) { 95 | data = [_cache objectForKey:key]; 96 | if (!data && [self existsDataForKey:key]) { 97 | data = [self _readFileAtURL:URLTo(key)]; 98 | if (data) 99 | [_cache setObject:data forKey:key]; 100 | } 101 | } 102 | return data; 103 | } 104 | 105 | - (void)writeDataOnDisk:(NSData *)data forKey:(NSString *)key { 106 | if (data && key) { 107 | [self _writeData:data atURL:URLTo(key)]; 108 | } 109 | } 110 | 111 | - (NSString *)storeDataForUndefinedKey:(NSData *)data { 112 | NSString *key = nil; 113 | if (data) { 114 | do { 115 | key = [self _generateKey]; 116 | } while (!key || (key && [self existsDataForKey:key])); 117 | 118 | [self writeDataOnDisk:data forKey:key]; 119 | } 120 | return key; 121 | } 122 | 123 | - (void)removeDataForKey:(NSString *)key { 124 | [_cache removeObjectForKey:key]; 125 | [self _removeDataAtURL:URLTo(key)]; 126 | } 127 | 128 | - (BOOL)existsDataForKey:(NSString *)key { 129 | return (key != nil) ? [self _existsFileAtURL:URLTo(key)] : NO; 130 | } 131 | 132 | - (NSArray *)allKeys { 133 | return [self _allFileNamesAtURL:_directoryURL]; 134 | } 135 | 136 | - (NSDictionary *)attributesOfFileForKey:(NSString *)key error:(NSError *__autoreleasing *)error { 137 | NSError *localError = nil; 138 | NSDictionary *attributes = [NSDictionary dictionary]; 139 | if (key) { 140 | NSDictionary *tmpAttributes = [self _attributesOfFileAtURL:URLTo(key) error:&localError]; 141 | if (tmpAttributes) { 142 | attributes = tmpAttributes; 143 | } 144 | 145 | if (localError && error) { 146 | *error = localError; 147 | } 148 | } 149 | 150 | return attributes; 151 | } 152 | 153 | + (NSURL *)_temporaryDirectoryURL { 154 | return [NSURL fileURLWithPath:NSTemporaryDirectory()]; 155 | } 156 | 157 | - (NSString *)_generateKey { 158 | return [[NSUUID UUID] UUIDString]; 159 | } 160 | 161 | @end 162 | 163 | @implementation TSFileCache (Subscript) 164 | 165 | - (NSData *)objectForKeyedSubscript:(NSString *)key { 166 | return [self dataForKey:key]; 167 | } 168 | 169 | - (void)setObject:(NSData *)data forKeyedSubscript:(NSString *)key { 170 | [self writeDataOnDisk:data forKey:key]; 171 | } 172 | 173 | @end 174 | 175 | @implementation TSFileCache (Prepare) 176 | - (BOOL)_prepareWithDirectoryAtURL:(NSURL *)directoryURL error:(NSError *__autoreleasing *)error { 177 | NSError *localError = nil; 178 | /// Check if file exists and create directory if necessary 179 | NSFileManager *fileManager = [NSFileManager defaultManager]; 180 | BOOL isDirectory = NO; 181 | BOOL fileExists = [fileManager fileExistsAtPath:[directoryURL path] isDirectory:&isDirectory]; 182 | if (fileExists) { 183 | if (!isDirectory) { 184 | localError = [NSError _tsfc_errorWithDescription:[NSString stringWithFormat:@"File at path %@ exists and it is not directory. Cannot create directory here.", [directoryURL path]]]; 185 | } 186 | } else { 187 | NSError *createDirectoryError = nil; 188 | [fileManager createDirectoryAtURL:directoryURL withIntermediateDirectories:YES attributes:nil error:&createDirectoryError]; 189 | if (createDirectoryError) { 190 | localError = [NSError _tsfc_errorWithDescription:createDirectoryError.localizedDescription]; 191 | } 192 | } 193 | 194 | /// Return error if occured 195 | if (localError && error) { 196 | *error = localError; 197 | } 198 | 199 | return (localError == nil); 200 | } 201 | 202 | @end 203 | 204 | @implementation TSFileCache (StorageManager) 205 | 206 | - (BOOL)_existsFileAtURL:(NSURL *)fileURL { 207 | return [[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]; 208 | } 209 | 210 | - (NSData *)_readFileAtURL:(NSURL *)fileURL { 211 | return [[NSData alloc] initWithContentsOfURL:fileURL options:NSDataReadingUncached error:nil]; 212 | } 213 | 214 | - (void)_writeData:(NSData *)data atURL:(NSURL *)fileURL { 215 | [data writeToURL:fileURL atomically:YES]; 216 | } 217 | 218 | - (void)_removeDataAtURL:(NSURL *)fileURL { 219 | [[NSFileManager defaultManager] removeItemAtURL:fileURL error:nil]; 220 | } 221 | 222 | - (void)_clearDirectoryAtURL:(NSURL *)directoryURL { 223 | NSFileManager *fileManager = [NSFileManager defaultManager]; 224 | NSArray *fileNames = [self _allFileNamesAtURL:directoryURL]; 225 | for (NSString *fileName in fileNames) { 226 | [fileManager removeItemAtPath:[[directoryURL URLByAppendingPathComponent:fileName] path] error:nil]; 227 | } 228 | } 229 | 230 | - (NSArray *)_allFileNamesAtURL:(NSURL *)directoryURL { 231 | NSFileManager *fileManager = [NSFileManager defaultManager]; 232 | NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:[directoryURL path]]; 233 | 234 | return [[enumerator allObjects] copy]; 235 | } 236 | 237 | - (NSDictionary *)_attributesOfFileAtURL:(NSURL *)fileURL error:(NSError *__autoreleasing *)error { 238 | NSError *localError = nil; 239 | NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[fileURL path] error:&localError]; 240 | if (localError && error) { 241 | *error = localError; 242 | } 243 | 244 | return attributes; 245 | } 246 | 247 | @end 248 | 249 | 250 | @implementation NSURL (TSFileCache) 251 | 252 | - (NSURL *)_tsfc_appendURL:(NSURL *)url { 253 | NSString *absoluteString = [url absoluteString]; 254 | if ([absoluteString rangeOfString:@"/"].location == 0) { 255 | absoluteString = [absoluteString substringFromIndex:1]; 256 | } 257 | 258 | return [self URLByAppendingPathComponent:absoluteString]; 259 | } 260 | 261 | @end 262 | 263 | @implementation NSError (TSFileCache) 264 | 265 | + (NSError *)_tsfc_errorWithDescription:(NSString *)description { 266 | NSDictionary *info = @{NSLocalizedDescriptionKey : description}; 267 | return [NSError errorWithDomain:TSFileCacheErrorDomain code:-1 userInfo:info]; 268 | } 269 | 270 | @end 271 | -------------------------------------------------------------------------------- /Classes/TSImageCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleImageCache.h 3 | // TSFileCache 4 | // 5 | // Created by Tomasz Szulc on 15/04/14. 6 | // Copyright (c) 2014 Tomasz Szulc. All rights reserved. 7 | // 8 | 9 | #import "TSFileCache.h" 10 | #import 11 | 12 | @interface TSImageCache : TSFileCache 13 | 14 | + (instancetype)sharedInstance; 15 | 16 | - (UIImage *)imageForKey:(NSString *)key; 17 | - (void)cacheImage:(UIImage *)image forKey:(NSString *)key; 18 | - (NSString *)cacheImageForUndefinedKey:(UIImage *)image store:(BOOL)store; 19 | - (void)clear; 20 | 21 | 22 | #pragma mark - unavailable 23 | + (void)setSharedInstance:(TSFileCache *)instance __TSFileCacheUnavailable__; 24 | + (instancetype)cacheForURL:(NSURL *)directoryURL __TSFileCacheUnavailable__; 25 | + (instancetype)cacheInTemporaryDirectoryWithRelativeURL:(NSURL *)relativeURL __TSFileCacheUnavailable__; 26 | - (NSData *)dataForKey:(NSString *)key __TSFileCacheUnavailable__; 27 | - (void)writeDataOnDisk:(NSData *)data forKey:(NSString *)key __TSFileCacheUnavailable__; 28 | 29 | @end 30 | 31 | @interface TSImageCache (Subscript) 32 | 33 | - (void)setObject:(UIImage *)image forKeyedSubscript:(NSString *)key; 34 | - (UIImage *)objectForKeyedSubscript:(NSString *)key; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Classes/TSImageCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleImageCache.m 3 | // TSFileCache 4 | // 5 | // Created by Tomasz Szulc on 15/04/14. 6 | // Copyright (c) 2014 Tomasz Szulc. All rights reserved. 7 | // 8 | 9 | #import "TSImageCache.h" 10 | 11 | @implementation TSImageCache 12 | 13 | static TSImageCache *_sharedInstance = nil; 14 | + (instancetype)sharedInstance { 15 | if (!_sharedInstance) { 16 | _sharedInstance = [super cacheInTemporaryDirectoryWithRelativeURL:[NSURL fileURLWithPath:@"/Cache/Images"]]; 17 | /// Prepare directory 18 | [_sharedInstance prepare:nil]; 19 | } 20 | return _sharedInstance; 21 | } 22 | 23 | - (UIImage *)imageForKey:(NSString *)key { 24 | UIImage *image = [self.cache objectForKey:key]; 25 | if (key && !image) { 26 | if ([self existsDataForKey:key]) { 27 | NSData *data = [super dataForKey:key]; 28 | if (data) { 29 | image = [UIImage imageWithData:data]; 30 | [self.cache setObject:image forKey:key]; 31 | } 32 | } 33 | } 34 | return image; 35 | } 36 | 37 | - (void)cacheImage:(UIImage *)image forKey:(NSString *)key { 38 | [self.cache setObject:image forKey:key]; 39 | NSData *data = UIImagePNGRepresentation(image); 40 | [super writeDataOnDisk:data forKey:key]; 41 | } 42 | 43 | - (NSString *)cacheImageForUndefinedKey:(UIImage *)image store:(BOOL)store { 44 | NSData *data = UIImagePNGRepresentation(image); 45 | NSString *key = [super storeDataForUndefinedKey:data]; 46 | if (store) { 47 | [self.cache setObject:image forKey:key]; 48 | } 49 | return key; 50 | } 51 | 52 | - (void)clear { 53 | [super clear]; 54 | } 55 | 56 | @end 57 | 58 | @implementation TSImageCache (Subscript) 59 | 60 | - (void)setObject:(UIImage *)image forKeyedSubscript:(NSString *)key { 61 | [self cacheImage:image forKey:key]; 62 | } 63 | 64 | - (UIImage *)objectForKeyedSubscript:(NSString *)key { 65 | return [self imageForKey:key]; 66 | } 67 | 68 | @end -------------------------------------------------------------------------------- /Example/TSImageCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleImageCache.h 3 | // TSFileCache 4 | // 5 | // Created by Tomasz Szulc on 15/04/14. 6 | // Copyright (c) 2014 Tomasz Szulc. All rights reserved. 7 | // 8 | 9 | #import "TSFileCache.h" 10 | #import 11 | 12 | @interface TSImageCache : TSFileCache 13 | 14 | + (instancetype)sharedInstance; 15 | 16 | - (UIImage *)imageForKey:(NSString *)key; 17 | - (void)cacheImage:(UIImage *)image forKey:(NSString *)key; 18 | - (NSString *)cacheImageForUndefinedKey:(UIImage *)image store:(BOOL)store; 19 | - (void)clear; 20 | 21 | 22 | #pragma mark - unavailable 23 | + (void)setSharedInstance:(TSFileCache *)instance __TSFileCacheUnavailable__; 24 | + (instancetype)cacheForURL:(NSURL *)directoryURL __TSFileCacheUnavailable__; 25 | + (instancetype)cacheInTemporaryDirectoryWithRelativeURL:(NSURL *)relativeURL __TSFileCacheUnavailable__; 26 | - (NSData *)dataForKey:(NSString *)key __TSFileCacheUnavailable__; 27 | - (void)writeDataOnDisk:(NSData *)data forKey:(NSString *)key __TSFileCacheUnavailable__; 28 | 29 | @end 30 | 31 | @interface TSImageCache (Subscript) 32 | 33 | - (void)setObject:(UIImage *)image forKeyedSubscript:(NSString *)key; 34 | - (UIImage *)objectForKeyedSubscript:(NSString *)key; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Example/TSImageCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleImageCache.m 3 | // TSFileCache 4 | // 5 | // Created by Tomasz Szulc on 15/04/14. 6 | // Copyright (c) 2014 Tomasz Szulc. All rights reserved. 7 | // 8 | 9 | #import "TSImageCache.h" 10 | 11 | @implementation TSImageCache 12 | 13 | static TSImageCache *_sharedInstance = nil; 14 | + (instancetype)sharedInstance { 15 | if (!_sharedInstance) { 16 | _sharedInstance = [super cacheInTemporaryDirectoryWithRelativeURL:[NSURL fileURLWithPath:@"/Cache/Images"]]; 17 | /// Prepare directory 18 | [_sharedInstance prepare:nil]; 19 | } 20 | return _sharedInstance; 21 | } 22 | 23 | - (UIImage *)imageForKey:(NSString *)key { 24 | UIImage *image = [self.cache objectForKey:key]; 25 | if (key && !image) { 26 | if ([self existsDataForKey:key]) { 27 | NSData *data = [super dataForKey:key]; 28 | if (data) { 29 | image = [UIImage imageWithData:data]; 30 | [self.cache setObject:image forKey:key]; 31 | } 32 | } 33 | } 34 | return image; 35 | } 36 | 37 | - (void)cacheImage:(UIImage *)image forKey:(NSString *)key { 38 | [self.cache setObject:image forKey:key]; 39 | NSData *data = UIImagePNGRepresentation(image); 40 | [super writeDataOnDisk:data forKey:key]; 41 | } 42 | 43 | - (NSString *)cacheImageForUndefinedKey:(UIImage *)image store:(BOOL)store { 44 | NSData *data = UIImagePNGRepresentation(image); 45 | NSString *key = [super storeDataForUndefinedKey:data]; 46 | if (store) { 47 | [self.cache setObject:image forKey:key]; 48 | } 49 | return key; 50 | } 51 | 52 | - (void)clear { 53 | [super clear]; 54 | } 55 | 56 | @end 57 | 58 | @implementation TSImageCache (Subscript) 59 | 60 | - (void)setObject:(UIImage *)image forKeyedSubscript:(NSString *)key { 61 | [self cacheImage:image forKey:key]; 62 | } 63 | 64 | - (UIImage *)objectForKeyedSubscript:(NSString *)key { 65 | return [self imageForKey:key]; 66 | } 67 | 68 | @end -------------------------------------------------------------------------------- /Example/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomkowz/TSFileCache/bb65091f780aa40a4b5610cfe80461908657d352/Example/image.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | TSFileCache is available under the Apache 2.0 license. 2 | 3 | Copyright © 2014 Tomasz Szulc 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TSFileCache 2 | ======== 3 | `TSFileCache` is a simple generic class used to cache some sort of files on the disk - files that will be used later as e.g. icons in the cells of the table view, etc. 4 | 5 | 6 | Donate 7 | ========= 8 | If you like it... :) 9 | 10 | Flattr this 11 | 12 | 13 | How it works? 14 | ========= 15 | You create instance of a class by one of two designed initializers. You can create cache that uses some directory with method `cacheForURL:` but you can also (and I recommend that option) you method `cacheInTemporaryDirectoryWithRelativeURL:` which uses directory inside sandbox's temporary directory which is managed by system so you can forget about cleaning this directory. 16 | 17 | #### `+cacheForURL:` 18 | NSURL *directoryURL = [NSURL fileURLWithPath:...]; 19 | TSFileCache *cache = [TSFileCache cacheForURL:directoryURL]; 20 | 21 | #### `+cacheInTemporaryDirectoryWithRelativeURL:` 22 | NSURL *url = [NSURL URLWithString:@"/Cache"]; 23 | TSFileCache *cache = [TSFileCache cacheInTemporaryDirectoryWithRelativeURL:url]; 24 | 25 | After instance is created you have to call `prepare:` method. It prepares directory to work with files. If directory exists it do nothing, but if directory doesn't exists it try to create and return error if false (It's recommend to pass NSError object to the method parameter). 26 | 27 | ##### `-prepare:` 28 | TSFileCache *cache = [TSFileCache cacheInTemporaryDirectoryWithRelativeURL:[NSURL URLWithString:@"/Cache"]]; 29 | 30 | NSError *error = nil; 31 | [cache prepare:&error]; 32 | if (error) { 33 | /// do something here 34 | } 35 | 36 | Instance may be set as singleton via `setSharedInstance:` method and get by `sharedInstance`. You have to now that `sharedInstance` method does not create any instance of `TSFileCache` class - it simply return instance that has been set earlier by `setSharedInstance`, otherwise nil. 37 | 38 | #### `+setSharedInstance:` 39 | TSFileCache *cache = [TSFileCache cacheInTemporaryDirectoryWithRelativeURL:[NSURL URLWithString:@"/Cache/Icons"]]; 40 | [TSFileCache setSharedInstance:cache]; /// set 41 | 42 | #### `+sharedInstance` 43 | TSFileCache fileCache = [TSFileCache sharedInstance]; 44 | 45 | When instance is configured use `storeData:forKey:` to store data on disk, key is used as filename. If file for key exists file will be overwritten. 46 | To read data for key use `dataForKey:` method. If file for key doesn't exists nil will be returned. 47 | 48 | #### `-storeData:forKey:` 49 | UIImage *image = [UIImage imageNamed:@"image.png"]; 50 | NSData *data = UIImagePNGRepresentation(image); 51 | [cache storeData:data forKey:@"key"]; 52 | 53 | #### `-dataForKey:` 54 | NSData *data = [cache dataForKey:@"key"]; 55 | 56 | 57 | If you want to check if key is set and if file for this key is cached already use `existsDataForKey:` method instead of `dataForKey:`. The reason for that is that you may don't know how big is the cached file and it might take a lot of time to read this file. Instead there is only simply check if file exists. 58 | 59 | #### `-storeDataForUndefinedKey:` 60 | NSString *key = [cache storeDataForUndefinedKey:data]; 61 | 62 | You can also use method `-storeDataForUndefinedKey:` to store data if you don't know key with which data should be stored. The key will be generated and returned by method. Key is unique. 63 | 64 | #### `-removeDataForKey:` 65 | [cache removeDataForKey:key]; 66 | 67 | To remove cached file call `removeDataForKey`. 68 | 69 | 70 | #### `-existsDataForKey:` 71 | BOOL exists = [cache existsDataForKey:@"key"]; 72 | 73 | `TSFileCache` works also as a dictionary so you can do something like this: 74 | 75 | NSData *data = ...; 76 | _cache[key] = data; /// instead of [_cache storeData:data forKey:key]; 77 | id readData = _cache[key]; /// instead of [_cache dataForKey:key]; 78 | 79 | If you want to subclass `TSFileCache` and want to use this mechanism with other type than *NSData* you have to create the same methods but with other types - Check example. 80 | 81 | `TSFileCache` is using `NSCache` internally so when data is read first time value for this key is stored in `NSCache` and next time if data is still in the cache it will be used rather than reading again from the disk. System controlls `NSCache` instance and data can be removed from the cache anytime, and if you want to read again this data which was cached and now it is not `TSFileCache` will read this data from the disk and caches it again. 82 | 83 | If you want to clear directory when files are cached use `clear` method. Directory will be still there but it will be empty. 84 | 85 | #### `-clear` 86 | [cache clear]; 87 | 88 | I also added some macro which may be helpful during subclassing because probably some method will be not necessary to be available in the subclass. I use this macro with `TSImageCache` example in this repo. This macro is using `__attribute__(unavailable(...))` and prevents before calling method which should not be called on the subclass of `TSFileCache`. Macro is defined as `__TSFileCacheUnavailable__` and here is simple use of this: 89 | 90 | + (instancetype)cacheInTemporaryDirectoryWithRelativeURL:(NSURL *)relativeURL __TSFileCacheUnavailable__; 91 | 92 | #### `-allKeys` 93 | NSArray *keys = [cache allKeys]; 94 | 95 | Use `allKeys` method to get all keys inside cache directory. 96 | 97 | #### `-attributesOfFileForKey:error:` 98 | NSDictionary *attributes = [_fileCache attributesOfFileForKey:key error:nil]; 99 | 100 | Use this method to get attributes of cached files. 101 | 102 | 103 | CocoaPods 104 | ========= 105 | Class is available via the [CocoaPods](http://cocoapods.org). 106 | 107 | pod 'TSFileCache', '~> 1.0.4' 108 | 109 | Logs 110 | ===== 111 | **1.0.4**: 112 | 113 | - `cache` is now exposed as `readonly` property. Was private ivar. It has been exposed because of performance issues. Sometimes is better to store e.g. UIImage in cache instead of NSData and convert this NSData every time to UIImage. Please familiarize yourself with *TSImageCache* example. 114 | 115 | 116 | **1.0.3**: 117 | 118 | - added `-removeDataForKey:` method. 119 | 120 | 121 | **1.0.2**: 122 | 123 | - implemented `-storeDataForUndefinedKey:` method. 124 | 125 | - `-prepare:` method returns BOOL, earlier was void. It's because static code analyse warnings. 126 | 127 | - implemented `-allKeys` method. 128 | 129 | - implemented `-attributesOfFileForKey:error:`. 130 | 131 | 132 | **1.0.1**: 133 | 134 | - implemented subscripting. *TSFileCache* instance works as dictionary. instance[@"key"]; id data = instance[@"key"]; 135 | 136 | - added `existsDataForKey:` method to obtain if value for specified key exists. Added because of performance. 137 | 138 | - `directoryURL` property is not exposed as readonly (was hidden, but it may be useful to know path to directory with cached files), 139 | 140 | **1.0**: 141 | 142 | - *TSFileCache* released. 143 | 144 | License 145 | ====== 146 | 147 | TSFileCache is available under the Apache 2.0 license. 148 | 149 | Copyright © 2014 Tomasz Szulc 150 | 151 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 152 | 153 | http://www.apache.org/licenses/LICENSE-2.0 154 | 155 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 156 | -------------------------------------------------------------------------------- /TSFileCache.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "TSFileCache" 4 | s.version = "1.0.4" 5 | s.summary = "Generic class that allows you to cache files on device's disk. Need to cache images or other files? Check this. Easy to subclass and reuse." 6 | 7 | s.homepage = "https://github.com/tomkowz/TSFileCache" 8 | 9 | s.license = { :type => 'Apache', :file => 'LICENSE' } 10 | 11 | s.author = { "Tomasz Szulc" => "szulctomasz@me.com" } 12 | s.social_media_url = "http://twitter.com/tomkowz" 13 | 14 | s.platform = :ios, '6.0' 15 | 16 | s.source = { :git => "https://github.com/tomkowz/TSFileCache.git", :tag => "1.0.4" } 17 | 18 | s.source_files = 'Classes', 'Classes/**/*.{h,m}' 19 | s.requires_arc = true 20 | 21 | end 22 | -------------------------------------------------------------------------------- /TSFileCache.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 12AC5EDC18FD8BB00021C767 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12AC5EDB18FD8BB00021C767 /* Foundation.framework */; }; 11 | 12AC5EDE18FD8BB00021C767 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12AC5EDD18FD8BB00021C767 /* CoreGraphics.framework */; }; 12 | 12AC5EE018FD8BB00021C767 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12AC5EDF18FD8BB00021C767 /* UIKit.framework */; }; 13 | 12AC5EE618FD8BB00021C767 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 12AC5EE418FD8BB00021C767 /* InfoPlist.strings */; }; 14 | 12AC5EE818FD8BB00021C767 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 12AC5EE718FD8BB00021C767 /* main.m */; }; 15 | 12AC5EEC18FD8BB00021C767 /* TSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 12AC5EEB18FD8BB00021C767 /* TSAppDelegate.m */; }; 16 | 12AC5EF518FD8BB00021C767 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12AC5EF418FD8BB00021C767 /* XCTest.framework */; }; 17 | 12AC5EF618FD8BB00021C767 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12AC5EDB18FD8BB00021C767 /* Foundation.framework */; }; 18 | 12AC5EF718FD8BB00021C767 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12AC5EDF18FD8BB00021C767 /* UIKit.framework */; }; 19 | 12AC5EFF18FD8BB00021C767 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 12AC5EFD18FD8BB00021C767 /* InfoPlist.strings */; }; 20 | 12AC5F0118FD8BB00021C767 /* TSFileCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 12AC5F0018FD8BB00021C767 /* TSFileCacheTests.m */; }; 21 | 12AC5F0C18FD8C080021C767 /* TSFileCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 12AC5F0B18FD8C080021C767 /* TSFileCache.m */; }; 22 | 12AC5F1F18FDB0340021C767 /* TSImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 12AC5F1E18FDB0340021C767 /* TSImageCache.m */; }; 23 | 12E4AEB718FDE1210051AD9B /* image.png in Resources */ = {isa = PBXBuildFile; fileRef = 12E4AEB618FDE1210051AD9B /* image.png */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXContainerItemProxy section */ 27 | 12AC5EF818FD8BB00021C767 /* PBXContainerItemProxy */ = { 28 | isa = PBXContainerItemProxy; 29 | containerPortal = 12AC5ED018FD8BB00021C767 /* Project object */; 30 | proxyType = 1; 31 | remoteGlobalIDString = 12AC5ED718FD8BB00021C767; 32 | remoteInfo = TSFileCache; 33 | }; 34 | /* End PBXContainerItemProxy section */ 35 | 36 | /* Begin PBXFileReference section */ 37 | 12AC5ED818FD8BB00021C767 /* TSFileCache.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TSFileCache.app; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 12AC5EDB18FD8BB00021C767 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 39 | 12AC5EDD18FD8BB00021C767 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 40 | 12AC5EDF18FD8BB00021C767 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 41 | 12AC5EE318FD8BB00021C767 /* TSFileCache-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TSFileCache-Info.plist"; sourceTree = ""; }; 42 | 12AC5EE518FD8BB00021C767 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 43 | 12AC5EE718FD8BB00021C767 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 44 | 12AC5EE918FD8BB00021C767 /* TSFileCache-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TSFileCache-Prefix.pch"; sourceTree = ""; }; 45 | 12AC5EEA18FD8BB00021C767 /* TSAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TSAppDelegate.h; path = ../TSFileCache/TSAppDelegate.h; sourceTree = ""; }; 46 | 12AC5EEB18FD8BB00021C767 /* TSAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TSAppDelegate.m; path = ../TSFileCache/TSAppDelegate.m; sourceTree = ""; }; 47 | 12AC5EF318FD8BB00021C767 /* TSFileCacheTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TSFileCacheTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | 12AC5EF418FD8BB00021C767 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 49 | 12AC5EFC18FD8BB00021C767 /* TSFileCacheTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TSFileCacheTests-Info.plist"; sourceTree = ""; }; 50 | 12AC5EFE18FD8BB00021C767 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 51 | 12AC5F0018FD8BB00021C767 /* TSFileCacheTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TSFileCacheTests.m; sourceTree = ""; }; 52 | 12AC5F0A18FD8C080021C767 /* TSFileCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSFileCache.h; sourceTree = ""; }; 53 | 12AC5F0B18FD8C080021C767 /* TSFileCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSFileCache.m; sourceTree = ""; }; 54 | 12AC5F1D18FDB0340021C767 /* TSImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSImageCache.h; sourceTree = ""; }; 55 | 12AC5F1E18FDB0340021C767 /* TSImageCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSImageCache.m; sourceTree = ""; }; 56 | 12E4AEB618FDE1210051AD9B /* image.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = image.png; sourceTree = ""; }; 57 | /* End PBXFileReference section */ 58 | 59 | /* Begin PBXFrameworksBuildPhase section */ 60 | 12AC5ED518FD8BB00021C767 /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | 12AC5EDE18FD8BB00021C767 /* CoreGraphics.framework in Frameworks */, 65 | 12AC5EE018FD8BB00021C767 /* UIKit.framework in Frameworks */, 66 | 12AC5EDC18FD8BB00021C767 /* Foundation.framework in Frameworks */, 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | 12AC5EF018FD8BB00021C767 /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | 12AC5EF518FD8BB00021C767 /* XCTest.framework in Frameworks */, 75 | 12AC5EF718FD8BB00021C767 /* UIKit.framework in Frameworks */, 76 | 12AC5EF618FD8BB00021C767 /* Foundation.framework in Frameworks */, 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | /* End PBXFrameworksBuildPhase section */ 81 | 82 | /* Begin PBXGroup section */ 83 | 12AC5ECF18FD8BB00021C767 = { 84 | isa = PBXGroup; 85 | children = ( 86 | 12AC5F0D18FDA03E0021C767 /* Classes */, 87 | 12AC5F1C18FDB0150021C767 /* Example */, 88 | 12AC5EFA18FD8BB00021C767 /* TSFileCacheTests */, 89 | 12AC5EDA18FD8BB00021C767 /* Frameworks */, 90 | 12AC5ED918FD8BB00021C767 /* Products */, 91 | ); 92 | sourceTree = ""; 93 | }; 94 | 12AC5ED918FD8BB00021C767 /* Products */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 12AC5ED818FD8BB00021C767 /* TSFileCache.app */, 98 | 12AC5EF318FD8BB00021C767 /* TSFileCacheTests.xctest */, 99 | ); 100 | name = Products; 101 | sourceTree = ""; 102 | }; 103 | 12AC5EDA18FD8BB00021C767 /* Frameworks */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 12AC5EDB18FD8BB00021C767 /* Foundation.framework */, 107 | 12AC5EDD18FD8BB00021C767 /* CoreGraphics.framework */, 108 | 12AC5EDF18FD8BB00021C767 /* UIKit.framework */, 109 | 12AC5EF418FD8BB00021C767 /* XCTest.framework */, 110 | ); 111 | name = Frameworks; 112 | sourceTree = ""; 113 | }; 114 | 12AC5EE218FD8BB00021C767 /* Supporting Files */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 12AC5EE318FD8BB00021C767 /* TSFileCache-Info.plist */, 118 | 12AC5EE418FD8BB00021C767 /* InfoPlist.strings */, 119 | 12AC5EE718FD8BB00021C767 /* main.m */, 120 | 12AC5EE918FD8BB00021C767 /* TSFileCache-Prefix.pch */, 121 | ); 122 | name = "Supporting Files"; 123 | path = ../TSFileCache; 124 | sourceTree = ""; 125 | }; 126 | 12AC5EFA18FD8BB00021C767 /* TSFileCacheTests */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 12AC5F0018FD8BB00021C767 /* TSFileCacheTests.m */, 130 | 12AC5EFB18FD8BB00021C767 /* Supporting Files */, 131 | ); 132 | path = TSFileCacheTests; 133 | sourceTree = ""; 134 | }; 135 | 12AC5EFB18FD8BB00021C767 /* Supporting Files */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 12AC5EFC18FD8BB00021C767 /* TSFileCacheTests-Info.plist */, 139 | 12AC5EFD18FD8BB00021C767 /* InfoPlist.strings */, 140 | ); 141 | name = "Supporting Files"; 142 | sourceTree = ""; 143 | }; 144 | 12AC5F0D18FDA03E0021C767 /* Classes */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 12AC5F0A18FD8C080021C767 /* TSFileCache.h */, 148 | 12AC5F0B18FD8C080021C767 /* TSFileCache.m */, 149 | ); 150 | path = Classes; 151 | sourceTree = ""; 152 | }; 153 | 12AC5F1C18FDB0150021C767 /* Example */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 12AC5EEA18FD8BB00021C767 /* TSAppDelegate.h */, 157 | 12AC5EEB18FD8BB00021C767 /* TSAppDelegate.m */, 158 | 12E4AEB618FDE1210051AD9B /* image.png */, 159 | 12AC5F1D18FDB0340021C767 /* TSImageCache.h */, 160 | 12AC5F1E18FDB0340021C767 /* TSImageCache.m */, 161 | 12AC5EE218FD8BB00021C767 /* Supporting Files */, 162 | ); 163 | path = Example; 164 | sourceTree = ""; 165 | }; 166 | /* End PBXGroup section */ 167 | 168 | /* Begin PBXNativeTarget section */ 169 | 12AC5ED718FD8BB00021C767 /* TSFileCache */ = { 170 | isa = PBXNativeTarget; 171 | buildConfigurationList = 12AC5F0418FD8BB00021C767 /* Build configuration list for PBXNativeTarget "TSFileCache" */; 172 | buildPhases = ( 173 | 12AC5ED418FD8BB00021C767 /* Sources */, 174 | 12AC5ED518FD8BB00021C767 /* Frameworks */, 175 | 12AC5ED618FD8BB00021C767 /* Resources */, 176 | ); 177 | buildRules = ( 178 | ); 179 | dependencies = ( 180 | ); 181 | name = TSFileCache; 182 | productName = TSFileCache; 183 | productReference = 12AC5ED818FD8BB00021C767 /* TSFileCache.app */; 184 | productType = "com.apple.product-type.application"; 185 | }; 186 | 12AC5EF218FD8BB00021C767 /* TSFileCacheTests */ = { 187 | isa = PBXNativeTarget; 188 | buildConfigurationList = 12AC5F0718FD8BB00021C767 /* Build configuration list for PBXNativeTarget "TSFileCacheTests" */; 189 | buildPhases = ( 190 | 12AC5EEF18FD8BB00021C767 /* Sources */, 191 | 12AC5EF018FD8BB00021C767 /* Frameworks */, 192 | 12AC5EF118FD8BB00021C767 /* Resources */, 193 | ); 194 | buildRules = ( 195 | ); 196 | dependencies = ( 197 | 12AC5EF918FD8BB00021C767 /* PBXTargetDependency */, 198 | ); 199 | name = TSFileCacheTests; 200 | productName = TSFileCacheTests; 201 | productReference = 12AC5EF318FD8BB00021C767 /* TSFileCacheTests.xctest */; 202 | productType = "com.apple.product-type.bundle.unit-test"; 203 | }; 204 | /* End PBXNativeTarget section */ 205 | 206 | /* Begin PBXProject section */ 207 | 12AC5ED018FD8BB00021C767 /* Project object */ = { 208 | isa = PBXProject; 209 | attributes = { 210 | CLASSPREFIX = TS; 211 | LastUpgradeCheck = 0510; 212 | ORGANIZATIONNAME = "Tomasz Szulc"; 213 | TargetAttributes = { 214 | 12AC5ED718FD8BB00021C767 = { 215 | DevelopmentTeam = 7HTJY423B9; 216 | }; 217 | 12AC5EF218FD8BB00021C767 = { 218 | TestTargetID = 12AC5ED718FD8BB00021C767; 219 | }; 220 | }; 221 | }; 222 | buildConfigurationList = 12AC5ED318FD8BB00021C767 /* Build configuration list for PBXProject "TSFileCache" */; 223 | compatibilityVersion = "Xcode 3.2"; 224 | developmentRegion = English; 225 | hasScannedForEncodings = 0; 226 | knownRegions = ( 227 | en, 228 | ); 229 | mainGroup = 12AC5ECF18FD8BB00021C767; 230 | productRefGroup = 12AC5ED918FD8BB00021C767 /* Products */; 231 | projectDirPath = ""; 232 | projectRoot = ""; 233 | targets = ( 234 | 12AC5ED718FD8BB00021C767 /* TSFileCache */, 235 | 12AC5EF218FD8BB00021C767 /* TSFileCacheTests */, 236 | ); 237 | }; 238 | /* End PBXProject section */ 239 | 240 | /* Begin PBXResourcesBuildPhase section */ 241 | 12AC5ED618FD8BB00021C767 /* Resources */ = { 242 | isa = PBXResourcesBuildPhase; 243 | buildActionMask = 2147483647; 244 | files = ( 245 | 12AC5EE618FD8BB00021C767 /* InfoPlist.strings in Resources */, 246 | 12E4AEB718FDE1210051AD9B /* image.png in Resources */, 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | }; 250 | 12AC5EF118FD8BB00021C767 /* Resources */ = { 251 | isa = PBXResourcesBuildPhase; 252 | buildActionMask = 2147483647; 253 | files = ( 254 | 12AC5EFF18FD8BB00021C767 /* InfoPlist.strings in Resources */, 255 | ); 256 | runOnlyForDeploymentPostprocessing = 0; 257 | }; 258 | /* End PBXResourcesBuildPhase section */ 259 | 260 | /* Begin PBXSourcesBuildPhase section */ 261 | 12AC5ED418FD8BB00021C767 /* Sources */ = { 262 | isa = PBXSourcesBuildPhase; 263 | buildActionMask = 2147483647; 264 | files = ( 265 | 12AC5EE818FD8BB00021C767 /* main.m in Sources */, 266 | 12AC5F1F18FDB0340021C767 /* TSImageCache.m in Sources */, 267 | 12AC5F0C18FD8C080021C767 /* TSFileCache.m in Sources */, 268 | 12AC5EEC18FD8BB00021C767 /* TSAppDelegate.m in Sources */, 269 | ); 270 | runOnlyForDeploymentPostprocessing = 0; 271 | }; 272 | 12AC5EEF18FD8BB00021C767 /* Sources */ = { 273 | isa = PBXSourcesBuildPhase; 274 | buildActionMask = 2147483647; 275 | files = ( 276 | 12AC5F0118FD8BB00021C767 /* TSFileCacheTests.m in Sources */, 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | }; 280 | /* End PBXSourcesBuildPhase section */ 281 | 282 | /* Begin PBXTargetDependency section */ 283 | 12AC5EF918FD8BB00021C767 /* PBXTargetDependency */ = { 284 | isa = PBXTargetDependency; 285 | target = 12AC5ED718FD8BB00021C767 /* TSFileCache */; 286 | targetProxy = 12AC5EF818FD8BB00021C767 /* PBXContainerItemProxy */; 287 | }; 288 | /* End PBXTargetDependency section */ 289 | 290 | /* Begin PBXVariantGroup section */ 291 | 12AC5EE418FD8BB00021C767 /* InfoPlist.strings */ = { 292 | isa = PBXVariantGroup; 293 | children = ( 294 | 12AC5EE518FD8BB00021C767 /* en */, 295 | ); 296 | name = InfoPlist.strings; 297 | sourceTree = ""; 298 | }; 299 | 12AC5EFD18FD8BB00021C767 /* InfoPlist.strings */ = { 300 | isa = PBXVariantGroup; 301 | children = ( 302 | 12AC5EFE18FD8BB00021C767 /* en */, 303 | ); 304 | name = InfoPlist.strings; 305 | sourceTree = ""; 306 | }; 307 | /* End PBXVariantGroup section */ 308 | 309 | /* Begin XCBuildConfiguration section */ 310 | 12AC5F0218FD8BB00021C767 /* Debug */ = { 311 | isa = XCBuildConfiguration; 312 | buildSettings = { 313 | ALWAYS_SEARCH_USER_PATHS = NO; 314 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 315 | CLANG_CXX_LIBRARY = "libc++"; 316 | CLANG_ENABLE_MODULES = YES; 317 | CLANG_ENABLE_OBJC_ARC = YES; 318 | CLANG_WARN_BOOL_CONVERSION = YES; 319 | CLANG_WARN_CONSTANT_CONVERSION = YES; 320 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 321 | CLANG_WARN_EMPTY_BODY = YES; 322 | CLANG_WARN_ENUM_CONVERSION = YES; 323 | CLANG_WARN_INT_CONVERSION = YES; 324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 325 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 326 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 327 | COPY_PHASE_STRIP = NO; 328 | GCC_C_LANGUAGE_STANDARD = gnu99; 329 | GCC_DYNAMIC_NO_PIC = NO; 330 | GCC_OPTIMIZATION_LEVEL = 0; 331 | GCC_PREPROCESSOR_DEFINITIONS = ( 332 | "DEBUG=1", 333 | "$(inherited)", 334 | ); 335 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 336 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 337 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 338 | GCC_WARN_UNDECLARED_SELECTOR = YES; 339 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 340 | GCC_WARN_UNUSED_FUNCTION = YES; 341 | GCC_WARN_UNUSED_VARIABLE = YES; 342 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 343 | ONLY_ACTIVE_ARCH = YES; 344 | SDKROOT = iphoneos; 345 | TARGETED_DEVICE_FAMILY = "1,2"; 346 | }; 347 | name = Debug; 348 | }; 349 | 12AC5F0318FD8BB00021C767 /* Release */ = { 350 | isa = XCBuildConfiguration; 351 | buildSettings = { 352 | ALWAYS_SEARCH_USER_PATHS = NO; 353 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 354 | CLANG_CXX_LIBRARY = "libc++"; 355 | CLANG_ENABLE_MODULES = YES; 356 | CLANG_ENABLE_OBJC_ARC = YES; 357 | CLANG_WARN_BOOL_CONVERSION = YES; 358 | CLANG_WARN_CONSTANT_CONVERSION = YES; 359 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 360 | CLANG_WARN_EMPTY_BODY = YES; 361 | CLANG_WARN_ENUM_CONVERSION = YES; 362 | CLANG_WARN_INT_CONVERSION = YES; 363 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 364 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 365 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 366 | COPY_PHASE_STRIP = YES; 367 | ENABLE_NS_ASSERTIONS = NO; 368 | GCC_C_LANGUAGE_STANDARD = gnu99; 369 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 370 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 371 | GCC_WARN_UNDECLARED_SELECTOR = YES; 372 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 373 | GCC_WARN_UNUSED_FUNCTION = YES; 374 | GCC_WARN_UNUSED_VARIABLE = YES; 375 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 376 | SDKROOT = iphoneos; 377 | TARGETED_DEVICE_FAMILY = "1,2"; 378 | VALIDATE_PRODUCT = YES; 379 | }; 380 | name = Release; 381 | }; 382 | 12AC5F0518FD8BB00021C767 /* Debug */ = { 383 | isa = XCBuildConfiguration; 384 | buildSettings = { 385 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 386 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 387 | CODE_SIGN_IDENTITY = "iPhone Developer"; 388 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 389 | GCC_PREFIX_HEADER = "TSFileCache/TSFileCache-Prefix.pch"; 390 | INFOPLIST_FILE = "TSFileCache/TSFileCache-Info.plist"; 391 | PRODUCT_NAME = "$(TARGET_NAME)"; 392 | WRAPPER_EXTENSION = app; 393 | }; 394 | name = Debug; 395 | }; 396 | 12AC5F0618FD8BB00021C767 /* Release */ = { 397 | isa = XCBuildConfiguration; 398 | buildSettings = { 399 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 400 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 401 | CODE_SIGN_IDENTITY = "iPhone Developer"; 402 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 403 | GCC_PREFIX_HEADER = "TSFileCache/TSFileCache-Prefix.pch"; 404 | INFOPLIST_FILE = "TSFileCache/TSFileCache-Info.plist"; 405 | PRODUCT_NAME = "$(TARGET_NAME)"; 406 | WRAPPER_EXTENSION = app; 407 | }; 408 | name = Release; 409 | }; 410 | 12AC5F0818FD8BB00021C767 /* Debug */ = { 411 | isa = XCBuildConfiguration; 412 | buildSettings = { 413 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/TSFileCache.app/TSFileCache"; 414 | FRAMEWORK_SEARCH_PATHS = ( 415 | "$(SDKROOT)/Developer/Library/Frameworks", 416 | "$(inherited)", 417 | "$(DEVELOPER_FRAMEWORKS_DIR)", 418 | ); 419 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 420 | GCC_PREFIX_HEADER = "TSFileCache/TSFileCache-Prefix.pch"; 421 | GCC_PREPROCESSOR_DEFINITIONS = ( 422 | "DEBUG=1", 423 | "$(inherited)", 424 | ); 425 | INFOPLIST_FILE = "TSFileCacheTests/TSFileCacheTests-Info.plist"; 426 | PRODUCT_NAME = "$(TARGET_NAME)"; 427 | TEST_HOST = "$(BUNDLE_LOADER)"; 428 | WRAPPER_EXTENSION = xctest; 429 | }; 430 | name = Debug; 431 | }; 432 | 12AC5F0918FD8BB00021C767 /* Release */ = { 433 | isa = XCBuildConfiguration; 434 | buildSettings = { 435 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/TSFileCache.app/TSFileCache"; 436 | FRAMEWORK_SEARCH_PATHS = ( 437 | "$(SDKROOT)/Developer/Library/Frameworks", 438 | "$(inherited)", 439 | "$(DEVELOPER_FRAMEWORKS_DIR)", 440 | ); 441 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 442 | GCC_PREFIX_HEADER = "TSFileCache/TSFileCache-Prefix.pch"; 443 | INFOPLIST_FILE = "TSFileCacheTests/TSFileCacheTests-Info.plist"; 444 | PRODUCT_NAME = "$(TARGET_NAME)"; 445 | TEST_HOST = "$(BUNDLE_LOADER)"; 446 | WRAPPER_EXTENSION = xctest; 447 | }; 448 | name = Release; 449 | }; 450 | /* End XCBuildConfiguration section */ 451 | 452 | /* Begin XCConfigurationList section */ 453 | 12AC5ED318FD8BB00021C767 /* Build configuration list for PBXProject "TSFileCache" */ = { 454 | isa = XCConfigurationList; 455 | buildConfigurations = ( 456 | 12AC5F0218FD8BB00021C767 /* Debug */, 457 | 12AC5F0318FD8BB00021C767 /* Release */, 458 | ); 459 | defaultConfigurationIsVisible = 0; 460 | defaultConfigurationName = Release; 461 | }; 462 | 12AC5F0418FD8BB00021C767 /* Build configuration list for PBXNativeTarget "TSFileCache" */ = { 463 | isa = XCConfigurationList; 464 | buildConfigurations = ( 465 | 12AC5F0518FD8BB00021C767 /* Debug */, 466 | 12AC5F0618FD8BB00021C767 /* Release */, 467 | ); 468 | defaultConfigurationIsVisible = 0; 469 | defaultConfigurationName = Release; 470 | }; 471 | 12AC5F0718FD8BB00021C767 /* Build configuration list for PBXNativeTarget "TSFileCacheTests" */ = { 472 | isa = XCConfigurationList; 473 | buildConfigurations = ( 474 | 12AC5F0818FD8BB00021C767 /* Debug */, 475 | 12AC5F0918FD8BB00021C767 /* Release */, 476 | ); 477 | defaultConfigurationIsVisible = 0; 478 | defaultConfigurationName = Release; 479 | }; 480 | /* End XCConfigurationList section */ 481 | }; 482 | rootObject = 12AC5ED018FD8BB00021C767 /* Project object */; 483 | } 484 | -------------------------------------------------------------------------------- /TSFileCache.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TSFileCache.xcodeproj/xcuserdata/tomkowz_priv.xcuserdatad/xcschemes/TSFileCache.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /TSFileCache.xcodeproj/xcuserdata/tomkowz_priv.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TSFileCache.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 12AC5ED718FD8BB00021C767 16 | 17 | primary 18 | 19 | 20 | 12AC5EF218FD8BB00021C767 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /TSFileCache/TSAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // TSAppDelegate.h 3 | // TSFileCache 4 | // 5 | // Created by Tomasz Szulc on 15/04/14. 6 | // Copyright (c) 2014 Tomasz Szulc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TSAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /TSFileCache/TSAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // TSAppDelegate.m 3 | // TSFileCache 4 | // 5 | // Created by Tomasz Szulc on 15/04/14. 6 | // Copyright (c) 2014 Tomasz Szulc. All rights reserved. 7 | // 8 | 9 | #import "TSAppDelegate.h" 10 | #import "TSFileCache.h" 11 | #import "TSImageCache.h" 12 | 13 | @implementation TSAppDelegate 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 18 | // Override point for customization after application launch. 19 | self.window.backgroundColor = [UIColor whiteColor]; 20 | [self.window makeKeyAndVisible]; 21 | 22 | /// Test of TSFileCache 23 | [self firstTest]; 24 | 25 | /// Test of TSImageCache - It's example of subclassing. TSImageCache has interface prepared to store and read images like icons. 26 | // [self secondTest]; 27 | return YES; 28 | } 29 | 30 | - (void)firstTest { 31 | TSFileCache *cache = [TSFileCache cacheInTemporaryDirectoryWithRelativeURL:[NSURL URLWithString:@"/FileCache"]]; 32 | // [TSFileCache setSharedInstance:cache]; /// cache should be set as singleton 33 | [cache prepare:nil]; 34 | 35 | UIImage *image = [UIImage imageNamed:@"image.png"]; 36 | NSData *data = UIImagePNGRepresentation(image); 37 | /// save on disk 38 | for (int i = 0; i < 1000; i++) { 39 | [cache storeData:data forKey:[NSString stringWithFormat:@"image_%d", i]]; 40 | } 41 | 42 | /// read from disk 43 | for (int i = 0; i < 1000; i++) { 44 | [cache dataForKey:[NSString stringWithFormat:@"image_%d", i]]; 45 | 46 | } 47 | 48 | /// read from cache 49 | for (int i = 0; i < 1000; i++) { 50 | [cache dataForKey:[NSString stringWithFormat:@"image_%d", i]]; 51 | } 52 | 53 | /// subscript test 54 | NSString *str = @"This is a string to save"; 55 | NSData *strData = [str dataUsingEncoding:NSUTF8StringEncoding]; 56 | cache[@"str"] = strData; 57 | 58 | NSData *readStringData = cache[@"str"]; 59 | NSData *readStringDataTheSame = [cache dataForKey:@"str"]; 60 | NSLog(@"d1 = %lu, d2 = %lu", (unsigned long)[readStringData length], (unsigned long)[readStringDataTheSame length]); 61 | } 62 | 63 | - (void)secondTest { 64 | TSImageCache *imageCache = [TSImageCache sharedInstance]; 65 | UIImage *image = [UIImage imageNamed:@"image.png"]; 66 | /// store images 67 | for (int i = 0; i < 1000; i++) { 68 | [imageCache cacheImage:image forKey:[NSString stringWithFormat:@"image%d", i]]; 69 | } 70 | 71 | /// read from disk 72 | for (int i = 0; i < 1000; i++) { 73 | [imageCache imageForKey:[NSString stringWithFormat:@"image%d", i]]; 74 | } 75 | 76 | /// read from cache 77 | for (int i = 0; i < 1000; i += 2) { 78 | [imageCache cacheImage:image forKey:[NSString stringWithFormat:@"image%d", i]]; 79 | } 80 | 81 | /// subscript test 82 | UIImage *img = imageCache[@"image1"]; 83 | imageCache[@"image99999"] = img; 84 | UIImage *img2 = imageCache[@"image99999"]; 85 | NSLog(@"image is not nil: %d", img2 != nil); 86 | } 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /TSFileCache/TSFileCache-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.tomaszszulc.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /TSFileCache/TSFileCache-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /TSFileCache/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /TSFileCache/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TSFileCache 4 | // 5 | // Created by Tomasz Szulc on 15/04/14. 6 | // Copyright (c) 2014 Tomasz Szulc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "TSAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([TSAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /TSFileCacheTests/TSFileCacheTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.tomaszszulc.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /TSFileCacheTests/TSFileCacheTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // TSFileCacheTests.m 3 | // TSFileCacheTests 4 | // 5 | // Created by Tomasz Szulc on 15/04/14. 6 | // Copyright (c) 2014 Tomasz Szulc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TSFileCache.h" 11 | 12 | @interface TSFileCacheTests : XCTestCase 13 | 14 | @end 15 | 16 | static NSString * const mainTestDirectory = @"aslkdjfsalkdjfskfdl-sdfsasdfsalfkj9889990-sdfsdfsd"; 17 | 18 | @implementation TSFileCacheTests { 19 | TSFileCache *_fileCache; 20 | } 21 | 22 | - (void)setUp 23 | { 24 | [super setUp]; 25 | [TSFileCache setSharedInstance:nil]; 26 | _fileCache = [TSFileCache cacheForURL:[self testURL]]; 27 | [[NSFileManager defaultManager] removeItemAtURL:[self testURL] error:nil]; 28 | } 29 | 30 | - (void)tearDown 31 | { 32 | _fileCache = nil; 33 | [[NSFileManager defaultManager] removeItemAtURL:[self testURL] error:nil]; 34 | [TSFileCache setSharedInstance:nil]; 35 | [super tearDown]; 36 | } 37 | 38 | 39 | #pragma mark - cacheForURL: 40 | - (void)testThatInstanceShouldExistsForFileURL { 41 | XCTAssertNotNil([TSFileCache cacheForURL:[NSURL fileURLWithPath:NSTemporaryDirectory()]], @""); 42 | } 43 | 44 | - (void)testThatMethodShouldThrowExceptionForURLWhichIsNotFileURL { 45 | XCTAssertThrows([TSFileCache cacheForURL:[NSURL URLWithString:@"http://www.example.com"]], @""); 46 | } 47 | 48 | - (void)testThatMethodShouldThrowExceptionForNilURL { 49 | XCTAssertThrows([TSFileCache cacheForURL:nil], @""); 50 | } 51 | 52 | 53 | #pragma mark - cacheInTemporaryDirectoryWithRelativeURL 54 | - (void)testThatInstanceShouldExistsForRelativeURL { 55 | XCTAssertNotNil([TSFileCache cacheInTemporaryDirectoryWithRelativeURL:[NSURL URLWithString:@"Cache/Images"]], @""); 56 | } 57 | 58 | - (void)testThatInstanceShouldThrowExceptionForNilRelativeURL { 59 | XCTAssertThrows([TSFileCache cacheInTemporaryDirectoryWithRelativeURL:nil], @""); 60 | } 61 | 62 | #pragma mark - directoryURL 63 | - (void)testThatDirectoryURLPropertyIsNotNil { 64 | XCTAssertNotNil(_fileCache.directoryURL, @""); 65 | } 66 | 67 | 68 | #pragma mark - setSharedInstance: 69 | - (void)testThatSharedInstanceShouldBeSet { 70 | [TSFileCache setSharedInstance:_fileCache]; 71 | XCTAssertNotNil([TSFileCache sharedInstance], @""); 72 | } 73 | 74 | - (void)testThatSharedInstanceShouldBeNilIfNotSet { 75 | XCTAssertNil([TSFileCache sharedInstance], @""); 76 | } 77 | 78 | 79 | #pragma mark - prepare: 80 | - (void)testThatPrepareShouldEndWithoutError { 81 | NSError *prepareError = nil; 82 | BOOL success = [_fileCache prepare:&prepareError]; 83 | XCTAssertNil(prepareError, @""); 84 | XCTAssertTrue(success, @""); 85 | } 86 | 87 | - (void)testThatPrepareShouldEndWithErrorBecauseOfExistingFile { 88 | NSURL *testURL = [self testURL]; 89 | /// save file 90 | NSString *testString = @"This is a string"; 91 | NSData *data = [testString dataUsingEncoding:NSUTF8StringEncoding]; 92 | [data writeToURL:testURL atomically:YES]; 93 | 94 | NSError *prepareError = nil; 95 | BOOL success = [_fileCache prepare:&prepareError]; 96 | XCTAssertNotNil(prepareError, @""); 97 | XCTAssertFalse(success, @""); 98 | } 99 | 100 | 101 | #pragma mark - dataForKey: 102 | - (void)testThatDataShouldBeNilForNotExistingKey { 103 | [_fileCache prepare:nil]; 104 | XCTAssertNil([_fileCache dataForKey:@"Key"], @""); 105 | } 106 | 107 | 108 | #pragma mark - storeData:forKey: 109 | - (void)testThatDataShouldBeStored { 110 | [_fileCache prepare:nil]; 111 | 112 | /// store 113 | NSString *string = @"This is string to store"; 114 | NSData *dataToStore = [string dataUsingEncoding:NSUTF8StringEncoding]; 115 | [_fileCache storeData:dataToStore forKey:@"Key"]; 116 | 117 | TSFileCache *secondCache = [TSFileCache cacheForURL:[self testURL]]; 118 | [secondCache prepare:nil]; 119 | XCTAssertNotNil([secondCache dataForKey:@"Key"], @""); 120 | } 121 | 122 | 123 | #pragma mark - storeDataForAnonymousKey: 124 | - (void)testThatDataIsStoredCorrectlyAndKeyIsReturned { 125 | NSData *data = [@"This is a string to save" dataUsingEncoding:NSUTF8StringEncoding]; 126 | [_fileCache prepare:nil]; 127 | NSString *key = [_fileCache storeDataForUndefinedKey:data]; 128 | XCTAssertNotNil(key, @""); 129 | XCTAssertNotNil(_fileCache[key], @""); 130 | } 131 | 132 | 133 | #pragma mark - Subscript tests 134 | - (void)testThatDataCanBeSetViaSubscript { 135 | [_fileCache prepare:nil]; 136 | _fileCache[@"data"] = [NSData data]; 137 | XCTAssertNotNil(_fileCache[@"data"], @""); 138 | } 139 | 140 | 141 | #pragma mark - existsObjectForKey: 142 | - (void)testThatObjectExistsForKey { 143 | [_fileCache prepare:nil]; 144 | _fileCache[@"a"] = [NSData data]; 145 | XCTAssertTrue(_fileCache[@"a"], @""); 146 | XCTAssertFalse(_fileCache[@"b"], @""); 147 | } 148 | 149 | 150 | #pragma mark - removeDataForKey: 151 | - (void)testThatDataShouldBeRemoved { 152 | [_fileCache prepare:nil]; 153 | _fileCache[@"a"] = [NSData data]; 154 | [_fileCache removeDataForKey:@"a"]; 155 | XCTAssertFalse(_fileCache[@"a"], @""); 156 | } 157 | 158 | #pragma mark - clean 159 | - (void)testThatDataCacheShouldBeEmpty { 160 | NSString *string = @"This is a string which will be stored and removed later"; 161 | NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; 162 | 163 | [_fileCache prepare:nil]; 164 | [_fileCache storeData:data forKey:@"key1"]; 165 | [_fileCache storeData:data forKey:@"key2"]; 166 | [_fileCache storeData:data forKey:@"key3"]; 167 | 168 | [_fileCache clear]; 169 | 170 | XCTAssertNil([_fileCache dataForKey:@"key1"], @""); 171 | XCTAssertNil([_fileCache dataForKey:@"key2"], @""); 172 | XCTAssertNil([_fileCache dataForKey:@"key3"], @""); 173 | } 174 | 175 | - (NSURL *)testURL { 176 | return [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:mainTestDirectory]; 177 | } 178 | 179 | 180 | #pragma mark - allKeys 181 | - (void)testThatCorrectKeysShouldBeReturned { 182 | [_fileCache prepare:nil]; 183 | NSData *data = [@"this is a string" dataUsingEncoding:NSUTF8StringEncoding]; 184 | 185 | NSUInteger numberOfItems = 10; 186 | for (int i = 0; i < numberOfItems; i++) { 187 | [_fileCache storeDataForUndefinedKey:data]; 188 | } 189 | 190 | XCTAssertEqual([_fileCache allKeys].count, numberOfItems, @""); 191 | } 192 | 193 | - (void)testThatEmptyArrayShouldBeReturnedIfInContainerIsZeroElements { 194 | [_fileCache prepare:nil]; 195 | XCTAssertNotNil([_fileCache allKeys], @""); 196 | } 197 | 198 | 199 | #pragma mark - attributesOfFileForKey: 200 | - (void)testThatAttributesShouldBeReturned { 201 | [_fileCache prepare:nil]; 202 | NSData *data = [@"this is a string" dataUsingEncoding:NSUTF8StringEncoding]; 203 | NSString *key = [_fileCache storeDataForUndefinedKey:data]; 204 | 205 | NSDictionary *attributes = [_fileCache attributesOfFileForKey:key error:nil]; 206 | XCTAssertTrue([attributes allKeys].count > 0, @""); 207 | } 208 | 209 | @end 210 | -------------------------------------------------------------------------------- /TSFileCacheTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | --------------------------------------------------------------------------------