What is CodableCache? It's a framework that allows for seamless memory caching and disk persistence of your plain old Swift structs. Simply define a model and conform to Codable – you're ready to use CodableCache.
- Simple to use transparent cache based on keys and generic types
- Anything that's
Codableworks automatically - No serializers to write other than optional custom
Codableencode/decode - Works with images via codable wrapper
- Easy to integrate into existing workflows
- backed by battle tested NSCache and NSKeyedArchiver
- batteries included - by design, it's up to you to create workflows and handle cache errors
Codable Cache is a drop in replacement for my LeanCache framework, which was backed by specifying generic types conforming to NSCoding. It afforded workflows like let x: NSNumber? = Cache<NSNumber>("some interesting key") and that's still great, but writing serializers for NSCoding is a pain. Hence, CodableCache was born.
To get started, just import CodableCache, define a model that conforms to codable, and get coding. These are just a few examples of how you could use CodableCache.
import CodableCache structPerson:Codable{letname:Stringletage:Double // kids are half ages if you recall 😜 }finalclassPersonManager{letcache:CodableCache<Person>init(cacheKey:AnyHashable){ cache =CodableCache<Person>(key: cacheKey)}func getPerson()->Person?{return cache.get()}func set(person:Person)throws{ cache.set(value: person)}}varmyPerson=Person(name:"Andrew", age:26)letpersonManager=PersonManager(cacheKey:"myPerson")try? personManager.set(value: myPerson)iflet person = personManager.get(){print(person.name) // "Andrew" print(person.age) // 26 }import CodableCache //... structTestData:Codable{lettesting:[Int]}func saveJSON(){letjson="""{"testing": [ 1, 2, 3 ] }"""guardlet data = json.data(using:.utf8)else{return}letdecodedTestData:TestDatado{ decodedTestData =try decoder.decode(TestData.self, from: data)try codableCache.set(value: decodedTestData)}catch{ // do something else return}}import CodableCache finalclassAppDelegate:UIResponder,UIApplicationDelegate,UNUserNotificationCenterDelegate{letappSettings=CodableCache<Settings>(key:"com.myApp.settings")func application(_ application:UIApplication, didFinishLaunchingWithOptions launchOptions:[UIApplicationLaunchOptionsKey:Any]?)->Bool{iflet settings = appSettings.get(){doSomethingUseful(with: settings)}returntrue} // ... }import CodableCache structPerson:Codable{letname:Stringletage:Double} // this data will not be purged by the system like .cachesDirectory would letpersistentPersonStorage=CodableCache<Person>(key:"myPerson", directory:.applicationSupportDirectory)import CodableCache finalclassGenericCache<Cacheable:Codable>{letcache:CodableCache<Cacheable>init(cacheKey:AnyHashable){self.cache =CodableCache<Cacheable>(key: cacheKey)}func get()->Cacheable?{returnself.cache.get()}func set(value:Cacheable)throws{tryself.cache.set(value: value)}func clear()throws{tryself.cache.clear()}}letmyCache=GenericCache<MyType>(cacheKey:String(describing:MyType.self))Make sure you're decoding as optional if your values are optionally typed
func testCustomDecoder(){structFoo:Codable{varbar:String?=""privateenumCodingKeys:String,CodingKey{case bar }init(bar:String?){self.bar = bar }init(from decoder:Decoder)throws{letcontainer=try decoder.container(keyedBy:CodingKeys.self)self.bar =try container.decode(String.self, forKey:.bar)}func encode(to encoder:Encoder)throws{varcontainer= encoder.container(keyedBy:CodingKeys.self)try container.encode(self.bar, forKey:.bar)}}letfoo0=Foo(bar:"Hello World")letfoo1=Foo(bar:nil)letfooCache=CodableCache<Foo>(key:String(describing:Foo.self))try? fooCache.set(value: foo0) // this is not nil because decoder expected `String` XCTAssertNotNil(fooCache.get())try? fooCache.set(value: foo1) // this is nil because decoder expected `String`, but it was given what we'd expect for `String?` XCTAssertNil(fooCache.get())}To make the decoder work in this scenario, you would want to decode Foo.bar as String? like so:
self.bar =try container.decode(String?.self, forKey:.bar)Using something heavyweight like CoreData, Realm, or SQLite is often overkill. More often than not we're just backing up some local state based on some JSON interface – using a spaceship for a walk down the block 🚀. Typically, we display this data to the user if it isn't stale and update it from the network if need be. Sorting and reordering is often a server side task, so relational databases and object graphs might be too expensive in terms of upstart modeling and your management time. With CodableCache we take a different approach by allowing you to quickly define models, skip boilerplate / serializers, and start saving your data at a lightning pace.
CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:
$ gem install cocoapodsCocoaPods 1.1+ is required to build CodableCache.
To integrate CodableCache into your Xcode project using CocoaPods, specify it in your Podfile:
use_frameworks!target'<Your Target Name>'dopod'CodableCache'endThen, run the following command:
$ pod installCarthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
You can install Carthage with Homebrew using the following command:
$ brew update $ brew install carthageTo integrate CodableCache into your Xcode project using Carthage, specify it in your Cartfile:
github "asowers1/CodableCache" "master" Run
carthage update In your application targets “General” tab under the “Linked Frameworks and Libraries” section, drag and drop CodableCache-iOS.framework from the Carthage/Build/iOS directory that carthage update produced.
The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler. It is in early development, but Alamofire does support its use on supported platforms.
Once you have your Swift package set up, adding CodableCache as a dependency is as easy as adding it to the dependencies value of your Package.swift.
dependencies:[.Package(url:"https://github.com/asowers1/CodableCache.git")]Feel free to open an issue or pull request – I would be happy to help.
