├── .gitignore ├── Cache.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ ├── Cache-iOS.xcscheme │ ├── Cache-macOS.xcscheme │ ├── Cache-tvOS.xcscheme │ ├── Cache-watchOS.xcscheme │ └── xcschememanagement.plist ├── LICENSE ├── Package.swift ├── Readme.markdown ├── Sources └── Cache │ ├── AnyCache.swift │ ├── Box.swift │ ├── Cache.swift │ ├── DiskCache.swift │ ├── MemoryCache.swift │ └── MultiCache.swift └── Support ├── Cache.h └── Info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *xcuserdata/ 3 | *.mode1v3 4 | *.pbxuser 5 | *.xcworkspace 6 | .build 7 | -------------------------------------------------------------------------------- /Cache.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2139281F248806710009AFBF /* MemoryCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21392819248806710009AFBF /* MemoryCache.swift */; }; 11 | 21392820248806710009AFBF /* MemoryCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21392819248806710009AFBF /* MemoryCache.swift */; }; 12 | 21392821248806710009AFBF /* MemoryCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21392819248806710009AFBF /* MemoryCache.swift */; }; 13 | 21392822248806710009AFBF /* MemoryCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21392819248806710009AFBF /* MemoryCache.swift */; }; 14 | 21392823248806710009AFBF /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281A248806710009AFBF /* Box.swift */; }; 15 | 21392824248806710009AFBF /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281A248806710009AFBF /* Box.swift */; }; 16 | 21392825248806710009AFBF /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281A248806710009AFBF /* Box.swift */; }; 17 | 21392826248806710009AFBF /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281A248806710009AFBF /* Box.swift */; }; 18 | 21392827248806710009AFBF /* DiskCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281B248806710009AFBF /* DiskCache.swift */; }; 19 | 21392828248806710009AFBF /* DiskCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281B248806710009AFBF /* DiskCache.swift */; }; 20 | 21392829248806710009AFBF /* DiskCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281B248806710009AFBF /* DiskCache.swift */; }; 21 | 2139282A248806710009AFBF /* DiskCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281B248806710009AFBF /* DiskCache.swift */; }; 22 | 2139282B248806710009AFBF /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281C248806710009AFBF /* Cache.swift */; }; 23 | 2139282C248806710009AFBF /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281C248806710009AFBF /* Cache.swift */; }; 24 | 2139282D248806710009AFBF /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281C248806710009AFBF /* Cache.swift */; }; 25 | 2139282E248806710009AFBF /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281C248806710009AFBF /* Cache.swift */; }; 26 | 2139282F248806710009AFBF /* MultiCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281D248806710009AFBF /* MultiCache.swift */; }; 27 | 21392830248806710009AFBF /* MultiCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281D248806710009AFBF /* MultiCache.swift */; }; 28 | 21392831248806710009AFBF /* MultiCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281D248806710009AFBF /* MultiCache.swift */; }; 29 | 21392832248806710009AFBF /* MultiCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281D248806710009AFBF /* MultiCache.swift */; }; 30 | 21392833248806710009AFBF /* AnyCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281E248806710009AFBF /* AnyCache.swift */; }; 31 | 21392834248806710009AFBF /* AnyCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281E248806710009AFBF /* AnyCache.swift */; }; 32 | 21392835248806710009AFBF /* AnyCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281E248806710009AFBF /* AnyCache.swift */; }; 33 | 21392836248806710009AFBF /* AnyCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2139281E248806710009AFBF /* AnyCache.swift */; }; 34 | 215DB4F61DC37A2600034124 /* Cache.h in Headers */ = {isa = PBXBuildFile; fileRef = 21E8791F1CEA6CFE0046ACE2 /* Cache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 35 | 215DB4F71DC37A2600034124 /* Cache.h in Headers */ = {isa = PBXBuildFile; fileRef = 21E8791F1CEA6CFE0046ACE2 /* Cache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 36 | 21B505511CFF9E830067FB9A /* Cache.h in Headers */ = {isa = PBXBuildFile; fileRef = 21E8791F1CEA6CFE0046ACE2 /* Cache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 37 | 21E879271CEA6CFE0046ACE2 /* Cache.h in Headers */ = {isa = PBXBuildFile; fileRef = 21E8791F1CEA6CFE0046ACE2 /* Cache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 38 | /* End PBXBuildFile section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | 21256E2A1CEA6CCD003B9F67 /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 21392819248806710009AFBF /* MemoryCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MemoryCache.swift; sourceTree = ""; }; 43 | 2139281A248806710009AFBF /* Box.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Box.swift; sourceTree = ""; }; 44 | 2139281B248806710009AFBF /* DiskCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiskCache.swift; sourceTree = ""; }; 45 | 2139281C248806710009AFBF /* Cache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cache.swift; sourceTree = ""; }; 46 | 2139281D248806710009AFBF /* MultiCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiCache.swift; sourceTree = ""; }; 47 | 2139281E248806710009AFBF /* AnyCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyCache.swift; sourceTree = ""; }; 48 | 215DB4E11DC379F800034124 /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 215DB4EE1DC37A0100034124 /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | 21B505431CFF9E610067FB9A /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 21E8791F1CEA6CFE0046ACE2 /* Cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Cache.h; sourceTree = ""; }; 52 | 21E879201CEA6CFE0046ACE2 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | /* End PBXFileReference section */ 54 | 55 | /* Begin PBXFrameworksBuildPhase section */ 56 | 21256E261CEA6CCD003B9F67 /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | 215DB4DD1DC379F800034124 /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | 215DB4EA1DC37A0100034124 /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | ); 75 | runOnlyForDeploymentPostprocessing = 0; 76 | }; 77 | 21B5053F1CFF9E610067FB9A /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | /* End PBXFrameworksBuildPhase section */ 85 | 86 | /* Begin PBXGroup section */ 87 | 21256E201CEA6CCD003B9F67 = { 88 | isa = PBXGroup; 89 | children = ( 90 | 21E879171CEA6CFE0046ACE2 /* Sources */, 91 | 21E8791E1CEA6CFE0046ACE2 /* Support */, 92 | 21256E2B1CEA6CCD003B9F67 /* Products */, 93 | ); 94 | sourceTree = ""; 95 | usesTabs = 1; 96 | }; 97 | 21256E2B1CEA6CCD003B9F67 /* Products */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 21256E2A1CEA6CCD003B9F67 /* Cache.framework */, 101 | 21B505431CFF9E610067FB9A /* Cache.framework */, 102 | 215DB4E11DC379F800034124 /* Cache.framework */, 103 | 215DB4EE1DC37A0100034124 /* Cache.framework */, 104 | ); 105 | name = Products; 106 | sourceTree = ""; 107 | }; 108 | 21392818248806710009AFBF /* Cache */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 21392819248806710009AFBF /* MemoryCache.swift */, 112 | 2139281A248806710009AFBF /* Box.swift */, 113 | 2139281B248806710009AFBF /* DiskCache.swift */, 114 | 2139281C248806710009AFBF /* Cache.swift */, 115 | 2139281D248806710009AFBF /* MultiCache.swift */, 116 | 2139281E248806710009AFBF /* AnyCache.swift */, 117 | ); 118 | path = Cache; 119 | sourceTree = ""; 120 | }; 121 | 21E879171CEA6CFE0046ACE2 /* Sources */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 21392818248806710009AFBF /* Cache */, 125 | ); 126 | path = Sources; 127 | sourceTree = ""; 128 | }; 129 | 21E8791E1CEA6CFE0046ACE2 /* Support */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 21E8791F1CEA6CFE0046ACE2 /* Cache.h */, 133 | 21E879201CEA6CFE0046ACE2 /* Info.plist */, 134 | ); 135 | path = Support; 136 | sourceTree = ""; 137 | }; 138 | /* End PBXGroup section */ 139 | 140 | /* Begin PBXHeadersBuildPhase section */ 141 | 21256E271CEA6CCD003B9F67 /* Headers */ = { 142 | isa = PBXHeadersBuildPhase; 143 | buildActionMask = 2147483647; 144 | files = ( 145 | 21E879271CEA6CFE0046ACE2 /* Cache.h in Headers */, 146 | ); 147 | runOnlyForDeploymentPostprocessing = 0; 148 | }; 149 | 215DB4DE1DC379F800034124 /* Headers */ = { 150 | isa = PBXHeadersBuildPhase; 151 | buildActionMask = 2147483647; 152 | files = ( 153 | 215DB4F71DC37A2600034124 /* Cache.h in Headers */, 154 | ); 155 | runOnlyForDeploymentPostprocessing = 0; 156 | }; 157 | 215DB4EB1DC37A0100034124 /* Headers */ = { 158 | isa = PBXHeadersBuildPhase; 159 | buildActionMask = 2147483647; 160 | files = ( 161 | 215DB4F61DC37A2600034124 /* Cache.h in Headers */, 162 | ); 163 | runOnlyForDeploymentPostprocessing = 0; 164 | }; 165 | 21B505401CFF9E610067FB9A /* Headers */ = { 166 | isa = PBXHeadersBuildPhase; 167 | buildActionMask = 2147483647; 168 | files = ( 169 | 21B505511CFF9E830067FB9A /* Cache.h in Headers */, 170 | ); 171 | runOnlyForDeploymentPostprocessing = 0; 172 | }; 173 | /* End PBXHeadersBuildPhase section */ 174 | 175 | /* Begin PBXNativeTarget section */ 176 | 21256E291CEA6CCD003B9F67 /* Cache-iOS */ = { 177 | isa = PBXNativeTarget; 178 | buildConfigurationList = 21256E321CEA6CCD003B9F67 /* Build configuration list for PBXNativeTarget "Cache-iOS" */; 179 | buildPhases = ( 180 | 21256E251CEA6CCD003B9F67 /* Sources */, 181 | 21256E261CEA6CCD003B9F67 /* Frameworks */, 182 | 21256E271CEA6CCD003B9F67 /* Headers */, 183 | 21256E281CEA6CCD003B9F67 /* Resources */, 184 | ); 185 | buildRules = ( 186 | ); 187 | dependencies = ( 188 | ); 189 | name = "Cache-iOS"; 190 | productName = Cache; 191 | productReference = 21256E2A1CEA6CCD003B9F67 /* Cache.framework */; 192 | productType = "com.apple.product-type.framework"; 193 | }; 194 | 215DB4E01DC379F800034124 /* Cache-tvOS */ = { 195 | isa = PBXNativeTarget; 196 | buildConfigurationList = 215DB4E61DC379F800034124 /* Build configuration list for PBXNativeTarget "Cache-tvOS" */; 197 | buildPhases = ( 198 | 215DB4DC1DC379F800034124 /* Sources */, 199 | 215DB4DD1DC379F800034124 /* Frameworks */, 200 | 215DB4DE1DC379F800034124 /* Headers */, 201 | 215DB4DF1DC379F800034124 /* Resources */, 202 | ); 203 | buildRules = ( 204 | ); 205 | dependencies = ( 206 | ); 207 | name = "Cache-tvOS"; 208 | productName = "Cache-tvOS"; 209 | productReference = 215DB4E11DC379F800034124 /* Cache.framework */; 210 | productType = "com.apple.product-type.framework"; 211 | }; 212 | 215DB4ED1DC37A0100034124 /* Cache-watchOS */ = { 213 | isa = PBXNativeTarget; 214 | buildConfigurationList = 215DB4F31DC37A0100034124 /* Build configuration list for PBXNativeTarget "Cache-watchOS" */; 215 | buildPhases = ( 216 | 215DB4E91DC37A0100034124 /* Sources */, 217 | 215DB4EA1DC37A0100034124 /* Frameworks */, 218 | 215DB4EB1DC37A0100034124 /* Headers */, 219 | 215DB4EC1DC37A0100034124 /* Resources */, 220 | ); 221 | buildRules = ( 222 | ); 223 | dependencies = ( 224 | ); 225 | name = "Cache-watchOS"; 226 | productName = "Cache-watchOS"; 227 | productReference = 215DB4EE1DC37A0100034124 /* Cache.framework */; 228 | productType = "com.apple.product-type.framework"; 229 | }; 230 | 21B505421CFF9E610067FB9A /* Cache-macOS */ = { 231 | isa = PBXNativeTarget; 232 | buildConfigurationList = 21B5054A1CFF9E610067FB9A /* Build configuration list for PBXNativeTarget "Cache-macOS" */; 233 | buildPhases = ( 234 | 21B5053E1CFF9E610067FB9A /* Sources */, 235 | 21B5053F1CFF9E610067FB9A /* Frameworks */, 236 | 21B505401CFF9E610067FB9A /* Headers */, 237 | 21B505411CFF9E610067FB9A /* Resources */, 238 | ); 239 | buildRules = ( 240 | ); 241 | dependencies = ( 242 | ); 243 | name = "Cache-macOS"; 244 | productName = "Cache-OSX"; 245 | productReference = 21B505431CFF9E610067FB9A /* Cache.framework */; 246 | productType = "com.apple.product-type.framework"; 247 | }; 248 | /* End PBXNativeTarget section */ 249 | 250 | /* Begin PBXProject section */ 251 | 21256E211CEA6CCD003B9F67 /* Project object */ = { 252 | isa = PBXProject; 253 | attributes = { 254 | LastUpgradeCheck = 1150; 255 | ORGANIZATIONNAME = "Sam Soffes"; 256 | TargetAttributes = { 257 | 21256E291CEA6CCD003B9F67 = { 258 | CreatedOnToolsVersion = 7.3.1; 259 | DevelopmentTeamName = "Canvas Labs, Inc."; 260 | LastSwiftMigration = 0800; 261 | ProvisioningStyle = Manual; 262 | }; 263 | 215DB4E01DC379F800034124 = { 264 | CreatedOnToolsVersion = 8.1; 265 | ProvisioningStyle = Automatic; 266 | }; 267 | 215DB4ED1DC37A0100034124 = { 268 | CreatedOnToolsVersion = 8.1; 269 | ProvisioningStyle = Automatic; 270 | }; 271 | 21B505421CFF9E610067FB9A = { 272 | CreatedOnToolsVersion = 7.3.1; 273 | DevelopmentTeam = 676PZY29MZ; 274 | DevelopmentTeamName = "Canvas Labs, Inc."; 275 | ProvisioningStyle = Automatic; 276 | }; 277 | }; 278 | }; 279 | buildConfigurationList = 21256E241CEA6CCD003B9F67 /* Build configuration list for PBXProject "Cache" */; 280 | compatibilityVersion = "Xcode 3.2"; 281 | developmentRegion = en; 282 | hasScannedForEncodings = 0; 283 | knownRegions = ( 284 | en, 285 | Base, 286 | ); 287 | mainGroup = 21256E201CEA6CCD003B9F67; 288 | productRefGroup = 21256E2B1CEA6CCD003B9F67 /* Products */; 289 | projectDirPath = ""; 290 | projectRoot = ""; 291 | targets = ( 292 | 21256E291CEA6CCD003B9F67 /* Cache-iOS */, 293 | 21B505421CFF9E610067FB9A /* Cache-macOS */, 294 | 215DB4E01DC379F800034124 /* Cache-tvOS */, 295 | 215DB4ED1DC37A0100034124 /* Cache-watchOS */, 296 | ); 297 | }; 298 | /* End PBXProject section */ 299 | 300 | /* Begin PBXResourcesBuildPhase section */ 301 | 21256E281CEA6CCD003B9F67 /* Resources */ = { 302 | isa = PBXResourcesBuildPhase; 303 | buildActionMask = 2147483647; 304 | files = ( 305 | ); 306 | runOnlyForDeploymentPostprocessing = 0; 307 | }; 308 | 215DB4DF1DC379F800034124 /* Resources */ = { 309 | isa = PBXResourcesBuildPhase; 310 | buildActionMask = 2147483647; 311 | files = ( 312 | ); 313 | runOnlyForDeploymentPostprocessing = 0; 314 | }; 315 | 215DB4EC1DC37A0100034124 /* Resources */ = { 316 | isa = PBXResourcesBuildPhase; 317 | buildActionMask = 2147483647; 318 | files = ( 319 | ); 320 | runOnlyForDeploymentPostprocessing = 0; 321 | }; 322 | 21B505411CFF9E610067FB9A /* Resources */ = { 323 | isa = PBXResourcesBuildPhase; 324 | buildActionMask = 2147483647; 325 | files = ( 326 | ); 327 | runOnlyForDeploymentPostprocessing = 0; 328 | }; 329 | /* End PBXResourcesBuildPhase section */ 330 | 331 | /* Begin PBXSourcesBuildPhase section */ 332 | 21256E251CEA6CCD003B9F67 /* Sources */ = { 333 | isa = PBXSourcesBuildPhase; 334 | buildActionMask = 2147483647; 335 | files = ( 336 | 2139281F248806710009AFBF /* MemoryCache.swift in Sources */, 337 | 21392823248806710009AFBF /* Box.swift in Sources */, 338 | 2139282B248806710009AFBF /* Cache.swift in Sources */, 339 | 21392833248806710009AFBF /* AnyCache.swift in Sources */, 340 | 21392827248806710009AFBF /* DiskCache.swift in Sources */, 341 | 2139282F248806710009AFBF /* MultiCache.swift in Sources */, 342 | ); 343 | runOnlyForDeploymentPostprocessing = 0; 344 | }; 345 | 215DB4DC1DC379F800034124 /* Sources */ = { 346 | isa = PBXSourcesBuildPhase; 347 | buildActionMask = 2147483647; 348 | files = ( 349 | 21392821248806710009AFBF /* MemoryCache.swift in Sources */, 350 | 21392825248806710009AFBF /* Box.swift in Sources */, 351 | 2139282D248806710009AFBF /* Cache.swift in Sources */, 352 | 21392835248806710009AFBF /* AnyCache.swift in Sources */, 353 | 21392829248806710009AFBF /* DiskCache.swift in Sources */, 354 | 21392831248806710009AFBF /* MultiCache.swift in Sources */, 355 | ); 356 | runOnlyForDeploymentPostprocessing = 0; 357 | }; 358 | 215DB4E91DC37A0100034124 /* Sources */ = { 359 | isa = PBXSourcesBuildPhase; 360 | buildActionMask = 2147483647; 361 | files = ( 362 | 21392822248806710009AFBF /* MemoryCache.swift in Sources */, 363 | 21392826248806710009AFBF /* Box.swift in Sources */, 364 | 2139282E248806710009AFBF /* Cache.swift in Sources */, 365 | 21392836248806710009AFBF /* AnyCache.swift in Sources */, 366 | 2139282A248806710009AFBF /* DiskCache.swift in Sources */, 367 | 21392832248806710009AFBF /* MultiCache.swift in Sources */, 368 | ); 369 | runOnlyForDeploymentPostprocessing = 0; 370 | }; 371 | 21B5053E1CFF9E610067FB9A /* Sources */ = { 372 | isa = PBXSourcesBuildPhase; 373 | buildActionMask = 2147483647; 374 | files = ( 375 | 21392820248806710009AFBF /* MemoryCache.swift in Sources */, 376 | 21392824248806710009AFBF /* Box.swift in Sources */, 377 | 2139282C248806710009AFBF /* Cache.swift in Sources */, 378 | 21392834248806710009AFBF /* AnyCache.swift in Sources */, 379 | 21392828248806710009AFBF /* DiskCache.swift in Sources */, 380 | 21392830248806710009AFBF /* MultiCache.swift in Sources */, 381 | ); 382 | runOnlyForDeploymentPostprocessing = 0; 383 | }; 384 | /* End PBXSourcesBuildPhase section */ 385 | 386 | /* Begin XCBuildConfiguration section */ 387 | 21256E301CEA6CCD003B9F67 /* Debug */ = { 388 | isa = XCBuildConfiguration; 389 | buildSettings = { 390 | ALWAYS_SEARCH_USER_PATHS = NO; 391 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 392 | CLANG_ANALYZER_NONNULL = YES; 393 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 394 | CLANG_CXX_LIBRARY = "libc++"; 395 | CLANG_ENABLE_MODULES = YES; 396 | CLANG_ENABLE_OBJC_ARC = YES; 397 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 398 | CLANG_WARN_BOOL_CONVERSION = YES; 399 | CLANG_WARN_COMMA = YES; 400 | CLANG_WARN_CONSTANT_CONVERSION = YES; 401 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 402 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 403 | CLANG_WARN_EMPTY_BODY = YES; 404 | CLANG_WARN_ENUM_CONVERSION = YES; 405 | CLANG_WARN_INFINITE_RECURSION = YES; 406 | CLANG_WARN_INT_CONVERSION = YES; 407 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 408 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 409 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 410 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 411 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 412 | CLANG_WARN_STRICT_PROTOTYPES = YES; 413 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 414 | CLANG_WARN_UNREACHABLE_CODE = YES; 415 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 416 | COPY_PHASE_STRIP = NO; 417 | CURRENT_PROJECT_VERSION = 1; 418 | DEBUG_INFORMATION_FORMAT = dwarf; 419 | ENABLE_STRICT_OBJC_MSGSEND = YES; 420 | ENABLE_TESTABILITY = YES; 421 | GCC_C_LANGUAGE_STANDARD = gnu99; 422 | GCC_DYNAMIC_NO_PIC = NO; 423 | GCC_NO_COMMON_BLOCKS = YES; 424 | GCC_OPTIMIZATION_LEVEL = 0; 425 | GCC_PREPROCESSOR_DEFINITIONS = ( 426 | "DEBUG=1", 427 | "$(inherited)", 428 | ); 429 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 430 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 431 | GCC_WARN_UNDECLARED_SELECTOR = YES; 432 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 433 | GCC_WARN_UNUSED_FUNCTION = YES; 434 | GCC_WARN_UNUSED_VARIABLE = YES; 435 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 436 | MACOSX_DEPLOYMENT_TARGET = 10.10; 437 | MTL_ENABLE_DEBUG_INFO = YES; 438 | ONLY_ACTIVE_ARCH = YES; 439 | SDKROOT = iphoneos; 440 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 441 | SWIFT_VERSION = 5.0; 442 | TARGETED_DEVICE_FAMILY = "1,2"; 443 | VERSIONING_SYSTEM = "apple-generic"; 444 | VERSION_INFO_PREFIX = ""; 445 | }; 446 | name = Debug; 447 | }; 448 | 21256E311CEA6CCD003B9F67 /* Release */ = { 449 | isa = XCBuildConfiguration; 450 | buildSettings = { 451 | ALWAYS_SEARCH_USER_PATHS = NO; 452 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 453 | CLANG_ANALYZER_NONNULL = YES; 454 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 455 | CLANG_CXX_LIBRARY = "libc++"; 456 | CLANG_ENABLE_MODULES = YES; 457 | CLANG_ENABLE_OBJC_ARC = YES; 458 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 459 | CLANG_WARN_BOOL_CONVERSION = YES; 460 | CLANG_WARN_COMMA = YES; 461 | CLANG_WARN_CONSTANT_CONVERSION = YES; 462 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 463 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 464 | CLANG_WARN_EMPTY_BODY = YES; 465 | CLANG_WARN_ENUM_CONVERSION = YES; 466 | CLANG_WARN_INFINITE_RECURSION = YES; 467 | CLANG_WARN_INT_CONVERSION = YES; 468 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 469 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 470 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 471 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 472 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 473 | CLANG_WARN_STRICT_PROTOTYPES = YES; 474 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 475 | CLANG_WARN_UNREACHABLE_CODE = YES; 476 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 477 | COPY_PHASE_STRIP = NO; 478 | CURRENT_PROJECT_VERSION = 1; 479 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 480 | ENABLE_NS_ASSERTIONS = NO; 481 | ENABLE_STRICT_OBJC_MSGSEND = YES; 482 | GCC_C_LANGUAGE_STANDARD = gnu99; 483 | GCC_NO_COMMON_BLOCKS = YES; 484 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 485 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 486 | GCC_WARN_UNDECLARED_SELECTOR = YES; 487 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 488 | GCC_WARN_UNUSED_FUNCTION = YES; 489 | GCC_WARN_UNUSED_VARIABLE = YES; 490 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 491 | MACOSX_DEPLOYMENT_TARGET = 10.10; 492 | MTL_ENABLE_DEBUG_INFO = NO; 493 | SDKROOT = iphoneos; 494 | SWIFT_VERSION = 5.0; 495 | TARGETED_DEVICE_FAMILY = "1,2"; 496 | VALIDATE_PRODUCT = YES; 497 | VERSIONING_SYSTEM = "apple-generic"; 498 | VERSION_INFO_PREFIX = ""; 499 | }; 500 | name = Release; 501 | }; 502 | 21256E331CEA6CCD003B9F67 /* Debug */ = { 503 | isa = XCBuildConfiguration; 504 | buildSettings = { 505 | APPLICATION_EXTENSION_API_ONLY = YES; 506 | CODE_SIGN_STYLE = Manual; 507 | DEFINES_MODULE = YES; 508 | DEVELOPMENT_TEAM = ""; 509 | DYLIB_COMPATIBILITY_VERSION = 1; 510 | DYLIB_CURRENT_VERSION = 1; 511 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 512 | INFOPLIST_FILE = "$(SRCROOT)/Support/Info.plist"; 513 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 514 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 515 | MARKETING_VERSION = 0.3.2; 516 | PRODUCT_BUNDLE_IDENTIFIER = com.samsoffes.cache; 517 | PRODUCT_NAME = Cache; 518 | PROVISIONING_PROFILE_SPECIFIER = ""; 519 | "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; 520 | SKIP_INSTALL = YES; 521 | }; 522 | name = Debug; 523 | }; 524 | 21256E341CEA6CCD003B9F67 /* Release */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | APPLICATION_EXTENSION_API_ONLY = YES; 528 | DEFINES_MODULE = YES; 529 | DYLIB_COMPATIBILITY_VERSION = 1; 530 | DYLIB_CURRENT_VERSION = 1; 531 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 532 | INFOPLIST_FILE = "$(SRCROOT)/Support/Info.plist"; 533 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 534 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 535 | MARKETING_VERSION = 0.3.2; 536 | PRODUCT_BUNDLE_IDENTIFIER = com.samsoffes.cache; 537 | PRODUCT_NAME = Cache; 538 | SKIP_INSTALL = YES; 539 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 540 | }; 541 | name = Release; 542 | }; 543 | 215DB4E71DC379F800034124 /* Debug */ = { 544 | isa = XCBuildConfiguration; 545 | buildSettings = { 546 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 547 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 548 | CODE_SIGN_IDENTITY = ""; 549 | DEFINES_MODULE = YES; 550 | DYLIB_COMPATIBILITY_VERSION = 1; 551 | DYLIB_CURRENT_VERSION = 1; 552 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 553 | INFOPLIST_FILE = Support/Info.plist; 554 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 555 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 556 | PRODUCT_BUNDLE_IDENTIFIER = com.samsoffes.cache; 557 | PRODUCT_NAME = Cache; 558 | SDKROOT = appletvos; 559 | SKIP_INSTALL = YES; 560 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 561 | TARGETED_DEVICE_FAMILY = 3; 562 | TVOS_DEPLOYMENT_TARGET = 10.0; 563 | }; 564 | name = Debug; 565 | }; 566 | 215DB4E81DC379F800034124 /* Release */ = { 567 | isa = XCBuildConfiguration; 568 | buildSettings = { 569 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 570 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 571 | CODE_SIGN_IDENTITY = ""; 572 | DEFINES_MODULE = YES; 573 | DYLIB_COMPATIBILITY_VERSION = 1; 574 | DYLIB_CURRENT_VERSION = 1; 575 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 576 | INFOPLIST_FILE = Support/Info.plist; 577 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 578 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 579 | PRODUCT_BUNDLE_IDENTIFIER = com.samsoffes.cache; 580 | PRODUCT_NAME = Cache; 581 | SDKROOT = appletvos; 582 | SKIP_INSTALL = YES; 583 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 584 | TARGETED_DEVICE_FAMILY = 3; 585 | TVOS_DEPLOYMENT_TARGET = 10.0; 586 | }; 587 | name = Release; 588 | }; 589 | 215DB4F41DC37A0100034124 /* Debug */ = { 590 | isa = XCBuildConfiguration; 591 | buildSettings = { 592 | APPLICATION_EXTENSION_API_ONLY = YES; 593 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 594 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 595 | CODE_SIGN_IDENTITY = ""; 596 | DEFINES_MODULE = YES; 597 | DYLIB_COMPATIBILITY_VERSION = 1; 598 | DYLIB_CURRENT_VERSION = 1; 599 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 600 | INFOPLIST_FILE = Support/Info.plist; 601 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 602 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 603 | PRODUCT_BUNDLE_IDENTIFIER = com.samsoffes.cache; 604 | PRODUCT_NAME = Cache; 605 | SDKROOT = watchos; 606 | SKIP_INSTALL = YES; 607 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 608 | TARGETED_DEVICE_FAMILY = 4; 609 | WATCHOS_DEPLOYMENT_TARGET = 3.1; 610 | }; 611 | name = Debug; 612 | }; 613 | 215DB4F51DC37A0100034124 /* Release */ = { 614 | isa = XCBuildConfiguration; 615 | buildSettings = { 616 | APPLICATION_EXTENSION_API_ONLY = YES; 617 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 618 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 619 | CODE_SIGN_IDENTITY = ""; 620 | DEFINES_MODULE = YES; 621 | DYLIB_COMPATIBILITY_VERSION = 1; 622 | DYLIB_CURRENT_VERSION = 1; 623 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 624 | INFOPLIST_FILE = Support/Info.plist; 625 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 626 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 627 | PRODUCT_BUNDLE_IDENTIFIER = com.samsoffes.cache; 628 | PRODUCT_NAME = Cache; 629 | SDKROOT = watchos; 630 | SKIP_INSTALL = YES; 631 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 632 | TARGETED_DEVICE_FAMILY = 4; 633 | WATCHOS_DEPLOYMENT_TARGET = 3.1; 634 | }; 635 | name = Release; 636 | }; 637 | 21B505481CFF9E610067FB9A /* Debug */ = { 638 | isa = XCBuildConfiguration; 639 | buildSettings = { 640 | APPLICATION_EXTENSION_API_ONLY = YES; 641 | COMBINE_HIDPI_IMAGES = YES; 642 | DEFINES_MODULE = YES; 643 | DYLIB_COMPATIBILITY_VERSION = 1; 644 | DYLIB_CURRENT_VERSION = 1; 645 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 646 | FRAMEWORK_VERSION = A; 647 | INFOPLIST_FILE = "$(SRCROOT)/Support/Info.plist"; 648 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 649 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 650 | PRODUCT_BUNDLE_IDENTIFIER = com.samsoffes.cache; 651 | PRODUCT_NAME = Cache; 652 | SDKROOT = macosx; 653 | SKIP_INSTALL = YES; 654 | }; 655 | name = Debug; 656 | }; 657 | 21B505491CFF9E610067FB9A /* Release */ = { 658 | isa = XCBuildConfiguration; 659 | buildSettings = { 660 | APPLICATION_EXTENSION_API_ONLY = YES; 661 | COMBINE_HIDPI_IMAGES = YES; 662 | DEFINES_MODULE = YES; 663 | DYLIB_COMPATIBILITY_VERSION = 1; 664 | DYLIB_CURRENT_VERSION = 1; 665 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 666 | FRAMEWORK_VERSION = A; 667 | INFOPLIST_FILE = "$(SRCROOT)/Support/Info.plist"; 668 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 669 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 670 | PRODUCT_BUNDLE_IDENTIFIER = com.samsoffes.cache; 671 | PRODUCT_NAME = Cache; 672 | SDKROOT = macosx; 673 | SKIP_INSTALL = YES; 674 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 675 | }; 676 | name = Release; 677 | }; 678 | /* End XCBuildConfiguration section */ 679 | 680 | /* Begin XCConfigurationList section */ 681 | 21256E241CEA6CCD003B9F67 /* Build configuration list for PBXProject "Cache" */ = { 682 | isa = XCConfigurationList; 683 | buildConfigurations = ( 684 | 21256E301CEA6CCD003B9F67 /* Debug */, 685 | 21256E311CEA6CCD003B9F67 /* Release */, 686 | ); 687 | defaultConfigurationIsVisible = 0; 688 | defaultConfigurationName = Release; 689 | }; 690 | 21256E321CEA6CCD003B9F67 /* Build configuration list for PBXNativeTarget "Cache-iOS" */ = { 691 | isa = XCConfigurationList; 692 | buildConfigurations = ( 693 | 21256E331CEA6CCD003B9F67 /* Debug */, 694 | 21256E341CEA6CCD003B9F67 /* Release */, 695 | ); 696 | defaultConfigurationIsVisible = 0; 697 | defaultConfigurationName = Release; 698 | }; 699 | 215DB4E61DC379F800034124 /* Build configuration list for PBXNativeTarget "Cache-tvOS" */ = { 700 | isa = XCConfigurationList; 701 | buildConfigurations = ( 702 | 215DB4E71DC379F800034124 /* Debug */, 703 | 215DB4E81DC379F800034124 /* Release */, 704 | ); 705 | defaultConfigurationIsVisible = 0; 706 | defaultConfigurationName = Release; 707 | }; 708 | 215DB4F31DC37A0100034124 /* Build configuration list for PBXNativeTarget "Cache-watchOS" */ = { 709 | isa = XCConfigurationList; 710 | buildConfigurations = ( 711 | 215DB4F41DC37A0100034124 /* Debug */, 712 | 215DB4F51DC37A0100034124 /* Release */, 713 | ); 714 | defaultConfigurationIsVisible = 0; 715 | defaultConfigurationName = Release; 716 | }; 717 | 21B5054A1CFF9E610067FB9A /* Build configuration list for PBXNativeTarget "Cache-macOS" */ = { 718 | isa = XCConfigurationList; 719 | buildConfigurations = ( 720 | 21B505481CFF9E610067FB9A /* Debug */, 721 | 21B505491CFF9E610067FB9A /* Release */, 722 | ); 723 | defaultConfigurationIsVisible = 0; 724 | defaultConfigurationName = Release; 725 | }; 726 | /* End XCConfigurationList section */ 727 | }; 728 | rootObject = 21256E211CEA6CCD003B9F67 /* Project object */; 729 | } 730 | -------------------------------------------------------------------------------- /Cache.xcodeproj/xcshareddata/xcschemes/Cache-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Cache.xcodeproj/xcshareddata/xcschemes/Cache-macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Cache.xcodeproj/xcshareddata/xcschemes/Cache-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Cache.xcodeproj/xcshareddata/xcschemes/Cache-watchOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Cache.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SchemeUserState 5 | 6 | Cache.xcscheme 7 | 8 | 9 | SuppressBuildableAutocreation 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Sam Soffes, http://soff.es 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.2 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "Cache", 7 | products: [ 8 | .library(name: "Cache", targets: ["Cache"]) 9 | ], 10 | targets: [ 11 | .target(name: "Cache") 12 | ] 13 | ) 14 | -------------------------------------------------------------------------------- /Readme.markdown: -------------------------------------------------------------------------------- 1 | # Cache 2 | 3 | [![Version](https://img.shields.io/github/release/soffes/Cache.svg)](https://github.com/soffes/Cache/releases) 4 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 5 | 6 | A generic caching library for Swift. Cache depends on Foundation. 7 | 8 | This is still very much a work in progress. 9 | 10 | 11 | ## Usage 12 | 13 | Cache provides a simple `Cache` protocol: 14 | 15 | ```swift 16 | protocol Cache { 17 | associatedtype Element 18 | 19 | func get(key key: String, completion: (Element? -> Void)) 20 | func set(key key: String, value: Element, completion: (() -> Void)?) 21 | func remove(key key: String, completion: (() -> Void)?) 22 | func removeAll(completion completion: (() -> Void)?) 23 | } 24 | ``` 25 | 26 | There are two (well actually three, but we'll get there) provided caches: 27 | 28 | * `MemoryCache` — Backed by an `NSCache` 29 | * `DiskCache` — Backed by files on disk using `NSFileManager` 30 | 31 | Using both of these is exactly the same interface. 32 | 33 | ## MultiCache 34 | 35 | There is a third cache provided called `MultiCache`. This combines caches. 36 | 37 | ```swift 38 | let cache = MultiCache(caches: [memoryCache, diskCache]) 39 | cache.set(key: "foo", value: "bar") 40 | ``` 41 | 42 | This will write to all caches in parallel. When accessing the multi cache, it will go in order. In this example, it will try the memory cache and if there's a miss it will try the disk cache. If it were to find it in the disk cache, it will write it to all previous caches for faster future reads. 43 | 44 | 45 | ## Thanks 46 | 47 | Thanks to [Caleb Davenport](https://twitter.com/calebd) for unintentionally inspiring this and lots of help along the way. 48 | -------------------------------------------------------------------------------- /Sources/Cache/AnyCache.swift: -------------------------------------------------------------------------------- 1 | public struct AnyCache: Cache { 2 | 3 | // MARK: - Properties 4 | 5 | private let _get: (String, @escaping (Element?) -> Void) -> () 6 | private let _set: (String, Element, (() -> Void)?) -> () 7 | private let _remove: (String, (() -> Void)?) -> () 8 | private let _removeAll: ((() -> Void)?) -> () 9 | 10 | // MARK: - Initializers 11 | 12 | public init(_ cache: C) where Element == C.Element { 13 | _get = { cache.get(key: $0, completion: $1) } 14 | _set = { cache.set(key: $0, value: $1, completion: $2) } 15 | _remove = { cache.remove(key: $0, completion: $1) } 16 | _removeAll = { cache.removeAll(completion: $0) } 17 | } 18 | 19 | // MARK: - Cache 20 | 21 | public func get(key: String, completion: @escaping ((Element?) -> Void)) { 22 | _get(key, completion) 23 | } 24 | 25 | public func set(key: String, value: Element, completion: (() -> Void)? = nil) { 26 | _set(key, value, completion) 27 | } 28 | 29 | public func remove(key: String, completion: (() -> Void)? = nil) { 30 | _remove(key, completion) 31 | } 32 | 33 | public func removeAll(completion: (() -> Void)? = nil) { 34 | _removeAll(completion) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/Cache/Box.swift: -------------------------------------------------------------------------------- 1 | final class Box { 2 | 3 | // MARK: - Properties 4 | 5 | let value: T 6 | 7 | // MARK: - Initializers 8 | 9 | init(_ value: T) { 10 | self.value = value 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/Cache/Cache.swift: -------------------------------------------------------------------------------- 1 | public protocol Cache { 2 | associatedtype Element 3 | 4 | func get(key: String, completion: @escaping ((Element?) -> Void)) 5 | func set(key: String, value: Element, completion: (() -> Void)?) 6 | func remove(key: String, completion: (() -> Void)?) 7 | func removeAll(completion: (() -> Void)?) 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Cache/DiskCache.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Disk cache. All reads run concurrently. Writes wait for all other queue actions to finish and run one at a time 4 | /// using dispatch barriers. 5 | public struct DiskCache: Cache { 6 | 7 | // MARK: - Properties 8 | 9 | private let directory: String 10 | private let fileManager = FileManager() 11 | private let queue = DispatchQueue(label: "com.samsoffes.cache.disk-cache", attributes: .concurrent) 12 | 13 | // MARK: - Initializers 14 | 15 | public init?(directory: String) { 16 | var isDirectory: ObjCBool = false 17 | // Ensure the directory exists 18 | if fileManager.fileExists(atPath: directory, isDirectory: &isDirectory) && isDirectory.boolValue { 19 | self.directory = directory 20 | return 21 | } 22 | 23 | // Try to create the directory 24 | do { 25 | try fileManager.createDirectory(atPath: directory, withIntermediateDirectories: true, attributes: nil) 26 | self.directory = directory 27 | } catch {} 28 | 29 | return nil 30 | } 31 | 32 | // MARK: - Cache 33 | 34 | public func get(key: String, completion: @escaping ((Element?) -> Void)) { 35 | let path = pathForKey(key) 36 | 37 | coordinate { 38 | let value = NSKeyedUnarchiver.unarchiveObject(withFile: path) as? Element 39 | completion(value) 40 | } 41 | } 42 | 43 | public func set(key: String, value: Element, completion: (() -> Void)? = nil) { 44 | let path = pathForKey(key) 45 | let fileManager = self.fileManager 46 | 47 | coordinate(barrier: true) { 48 | if fileManager.fileExists(atPath: path) { 49 | do { 50 | try fileManager.removeItem(atPath: path) 51 | } catch {} 52 | } 53 | 54 | NSKeyedArchiver.archiveRootObject(value, toFile: path) 55 | } 56 | } 57 | 58 | public func remove(key: String, completion: (() -> Void)? = nil) { 59 | let path = pathForKey(key) 60 | let fileManager = self.fileManager 61 | 62 | coordinate { 63 | if fileManager.fileExists(atPath: path) { 64 | do { 65 | try fileManager.removeItem(atPath: path) 66 | } catch {} 67 | } 68 | } 69 | } 70 | 71 | public func removeAll(completion: (() -> Void)? = nil) { 72 | let fileManager = self.fileManager 73 | let directory = self.directory 74 | 75 | coordinate { 76 | guard let paths = try? fileManager.contentsOfDirectory(atPath: directory) else { return } 77 | 78 | for path in paths { 79 | do { 80 | try fileManager.removeItem(atPath: path) 81 | } catch {} 82 | } 83 | } 84 | } 85 | 86 | // MARK: - Private 87 | 88 | private func coordinate(barrier: Bool = false, block: @escaping () -> Void) { 89 | if barrier { 90 | queue.async(flags: .barrier, execute: block) 91 | return 92 | } 93 | 94 | queue.async(execute: block) 95 | } 96 | 97 | private func pathForKey(_ key: String) -> String { 98 | return (directory as NSString).appendingPathComponent(key) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Sources/Cache/MemoryCache.swift: -------------------------------------------------------------------------------- 1 | #if os(iOS) || os(tvOS) 2 | import UIKit 3 | #else 4 | import Foundation 5 | #endif 6 | 7 | public final class MemoryCache: Cache { 8 | 9 | // MARK: - Properties 10 | 11 | private let storage = NSCache>() 12 | 13 | // MARK: - Initializers 14 | 15 | #if os(iOS) || os(tvOS) 16 | public init(countLimit: Int? = nil, automaticallyRemoveAllObjects: Bool = false) { 17 | storage.countLimit = countLimit ?? 0 18 | 19 | if automaticallyRemoveAllObjects { 20 | let notificationCenter = NotificationCenter.default 21 | notificationCenter.addObserver(storage, selector: #selector(type(of: storage).removeAllObjects), name: UIApplication.didEnterBackgroundNotification, object: nil) 22 | notificationCenter.addObserver(storage, selector: #selector(type(of: storage).removeAllObjects), name: UIApplication.didReceiveMemoryWarningNotification, object: nil) 23 | } 24 | } 25 | #else 26 | public init(countLimit: Int? = nil) { 27 | storage.countLimit = countLimit ?? 0 28 | } 29 | #endif 30 | 31 | // MARK: - Cache 32 | 33 | public func set(key: String, value: Element, completion: (() -> Void)? = nil) { 34 | storage.setObject(Box(value), forKey: key as NSString) 35 | completion?() 36 | } 37 | 38 | public func get(key: String, completion: @escaping ((Element?) -> Void)) { 39 | let box = storage.object(forKey: key as NSString) 40 | let value = box.flatMap({ $0.value }) 41 | completion(value) 42 | } 43 | 44 | public func remove(key: String, completion: (() -> Void)? = nil) { 45 | storage.removeObject(forKey: key as NSString) 46 | completion?() 47 | } 48 | 49 | public func removeAll(completion: (() -> Void)? = nil) { 50 | storage.removeAllObjects() 51 | completion?() 52 | } 53 | 54 | // MARK: - Synchronous 55 | 56 | public subscript(key: String) -> Element? { 57 | get { 58 | return (storage.object(forKey: key as NSString))?.value 59 | } 60 | 61 | set(newValue) { 62 | if let newValue = newValue { 63 | storage.setObject(Box(newValue), forKey: key as NSString) 64 | } else { 65 | storage.removeObject(forKey: key as NSString) 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Sources/Cache/MultiCache.swift: -------------------------------------------------------------------------------- 1 | import libkern 2 | 3 | /// Reads from the first cache available. Writes to all caches in order. If there is a cache miss and the value is later 4 | /// found in a subsequent cache, it is written to all previous caches. 5 | public struct MultiCache: Cache { 6 | 7 | // MARK: - Properties 8 | 9 | public let caches: [AnyCache] 10 | 11 | // MARK: - Initializers 12 | 13 | public init(caches: [AnyCache]) { 14 | self.caches = caches 15 | } 16 | 17 | // MARK: - Cache 18 | 19 | public func set(key: String, value: Element, completion: (() -> Void)? = nil) { 20 | coordinate(block: { cache, finish in 21 | cache.set(key: key, value: value, completion: finish) 22 | }, completion: completion) 23 | } 24 | 25 | public func get(key: String, completion: @escaping ((Element?) -> Void)) { 26 | var misses = [AnyCache]() 27 | 28 | func finish(_ value: Element?) { 29 | // Found 30 | if let value = value { 31 | // Call completion with the value 32 | completion(value) 33 | 34 | // Fill previous caches that missed 35 | for miss in misses { 36 | miss.set(key: key, value: value) 37 | } 38 | return 39 | } 40 | 41 | // Not in any of the caches 42 | if misses.count + 1 == self.caches.count { 43 | completion(nil) 44 | return 45 | } 46 | 47 | // Not found in this cache 48 | misses.append(self.caches[misses.count]) 49 | 50 | // Try the next cache 51 | get(key: key, cacheIndex: misses.count, completion: finish) 52 | } 53 | 54 | // Try the first cache 55 | get(key: key, cacheIndex: 0, completion: finish) 56 | } 57 | 58 | public func remove(key: String, completion: (() -> Void)?) { 59 | coordinate(block: { cache, finish in 60 | cache.remove(key: key, completion: finish) 61 | }, completion: completion) 62 | } 63 | 64 | public func removeAll(completion: (() -> Void)?) { 65 | coordinate(block: { cache, finish in 66 | cache.removeAll(completion: finish) 67 | }, completion: completion) 68 | } 69 | 70 | // MARK: - Private 71 | 72 | // Calls the completion block after all messages to all caches are complete. 73 | private func coordinate(block: ((AnyCache, (() -> Void)?) -> Void), completion: (() -> Void)?) { 74 | // Count starts with the count of caches 75 | var count = Int32(caches.count) 76 | 77 | let finish: () -> () = { 78 | // Safely decrement the count 79 | OSAtomicCompareAndSwap32(count, count - 1, &count) 80 | 81 | // If the count is 0, we're received all of the callbacks. 82 | if count == 0 { 83 | // Call the completion 84 | completion?() 85 | } 86 | } 87 | 88 | // Kick off the work for each cache 89 | caches.forEach { block($0, finish) } 90 | } 91 | 92 | private func get(key: String, cacheIndex index: Int, completion: @escaping ((Element?) -> Void)) { 93 | caches[index].get(key: key, completion: completion) 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Support/Cache.h: -------------------------------------------------------------------------------- 1 | // 2 | // Cache.h 3 | // Cache 4 | // 5 | // Created by Sam Soffes on 5/16/16. 6 | // Copyright © 2016 Sam Soffes. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | //! Project version number for Cache. 12 | FOUNDATION_EXPORT double CacheVersionNumber; 13 | 14 | //! Project version string for Cache. 15 | FOUNDATION_EXPORT const unsigned char CacheVersionString[]; 16 | -------------------------------------------------------------------------------- /Support/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | --------------------------------------------------------------------------------