After reading and analyzing popular cache frameworks, let’s start our own. In previous parts, we get main components including data converter, cache protocol, memory cache, Disk Cache and Cache manager. First let’s give our own cache framework a name. We know naming is the most difficult in programming. How about Hoard? All the codes will be pushed to GitHub /Hoard. Please pay attention there are many compromises for simplicity. It’s not a Product Ready Framework.
Data converter
In this section, we build data converter protocol and extension for different types. We prefer Cache’s design on this part.
Cachable.swift
public protocol Cachable {
associatedtype CacheType
static func decode(_ data: Data) -> CacheType?
func encode() -> Data?
}
Copy the code
Then we need to extend the type we want to cache to conform the protocol.
UIImage+Cache.swift
extension UIImage: Cachable {
public typealias CacheType = UIImage
public static func decode(_ data: Data) -> CacheType? {
let image = UIImage(data: data)
return image
}
public func encode() -> Data? {
return hasAlpha
? UIImagePNGRepresentation(self)
: UIImageJPEGRepresentation(self, 1.0)
}
}
Copy the code
Cache protocol
Cache protocol defines common interfaces to manage objects in cache. We only define the least requirements for a cache to store, retrieve and remove objects.
public protocol Cache {
func store<T: Cachable>(key: String, object: T, completion: (() -> Void)?)
func retrieve<T: Cachable>(_ key: String, completion: @escaping (_ object: T?) -> Void)
func remove(_ key: String, completion: (() -> Void)?)
}
Copy the code
Memory Cache
Memory cache can simply be taken as wrapper for NSCache, it only delegates all jobs to NSCache.
MemoryCache.swift
class MemoryCache: Cache {
public let cache = NSCache<AnyObject, AnyObject>()
func store<T : Cachable>(key: String, object: T, completion: (() -> Void)?) {
cache.setObject(object as AnyObject, forKey: key as AnyObject)
completion?()
}
func retrieve<T : Cachable>(_ key: String, completion: @escaping (T?) -> Void) {
let object = cache.object(forKey: key as AnyObject) //as? Capsule
completion(object as? T)
}
func remove(_ key: String, completion: (() -> Void)?) {
cache.removeObject(forKey: key as AnyObject)
completion?()
}
}
Copy the code
Disk Cache
It’s a little complex for disk cache but basically they’re file operations like creating file, reading file and removing file. Please refer to DiskCache.swift in GitHub – NilStack/Hoard.
Cache Manager
It controls the complete workflow and coordinate memory cache and disk cache.
class Hoard: Cache { static let sharedCache = Hoard() let memoryCache = MemoryCache() let diskCache = DiskCache() public func store<T : Cachable>(key: String, object: T, completion: (() -> Void)?) {}... }Copy the code
Usage
Here is example code to use our small cache framework.
let imageURL = URL(string: "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png")! let image = try! UIImage(data: Data(contentsOf: imageURL)) let cache = Hoard.sharedCache cache.store(key: "image", object: image! , completion: nil) cache.retrieve(key: "image") { (image: UIImage?) in if let image = image { imageView.image = image } else { print("no image") } }Copy the code
You can find the complete codebase at GitHub – NilStack/Hoard. Hoard is only demo for this series and not product ready.
Thanks for your time.