SKCache — another ordinary cache. Almost.

综合技术 2017-11-15

Once upon a time there was a developer who wanted to save everything into one cache.

The idea came up when I was searching the internet for a caching library which can store each known type in Swift (like Int, String, Arrays, Sets, etc.). I looked and searched but couldn’t find what I needed anywhere. So I set a challenge — to create a caching library, which can store every possible type in Swift.

Having the idea now it was time to develop it. The problem was, I had no clue where to start. Every day I was like

Ideas were flying in and out of my head. I was overwhelmed and in the end burned out.

So one day I sat alone in my room with a glass of whiskey (yes, sometime alcohol helps me think better) and went over all the notes I made. It was then that I decided to introduce the SKObject. It will store a value of a type known in Swift under a specific type. People might think what I was thinking, but actualy the pricipe is straightforward. If you write

let object = SKObject(value: 'your value to store', forKey: 'your key under which the object will be stored')

you’ve already created the object which will be cached. Easy, right?

First challenge was completed, but now it was time for the tricky part — where to store all of the objects I want to cache? Should I use a dictionary or some other container? After a bit of a research and experimenting with different structures I finally found the perfect container — the NSCache. A dictionary or an array wouldn’t work in my case, because of the cost limit management which NSCache offers. Neither of them have it.

At first I was storing each object separately under the defined key. Choosing this approach I met problems with quickly reaching the limit of the NSCache and purging all existing objects. Again it was time for brain power. After reading some articles and reviewing other cache libraries I came up with the idea to collect all SKObjects in one array and store that array in the NSCache. Using such logic I never reached the limit and the items were never purged.

As the NSCache mimics the functionality of a dictionary I needed a unique identifier for the objects to be stored under. I chose to use the bundle indentifier of the project. Reason — using some predefined string wasn’t an appropriate approach due to some accessibility issues, so using the unique signiture of the project I was able to preserve the information without accedently overwriting it.

Adding or retrieving an object from the cache is actually pretty easy and straight forward. Assuming we have our SKObject we just need to call

SKCache.shared.add(object: ‘instance of your SKObject’)

to add it and

SKCache.shared.get(forKey: 'the key of the desired object')

to retrieve it.

You might be thinking is it that easy and I’ll give a simple answer — Yes!

After sorting out where to save the objects I thought I was ready to deploy my library, but I was wrong. Many other cache libraries also offer a disk cache. I asked myself “Should I be the same as the others?”. Some cached objects must live for one session so it is not necessary to store them on the disk. But others, like images or big data, must be saved for later reuse. So I decided to include a possibility to save objects to the disk.

As a starting point I decided how to represent the objects from the cache into objects on the disk. Then Swift 4 wasn’t out yet, but when Apple released it, it gave me more possibilities and at the end I came up with an idea to store all objects in files in the applications cache directory.

After sorting this out, a issue arised. Is it memory efficient to store only files to the disk? I might end up without any free disk space at the end. To solve this problem I decided to add an expiry date to each cache object, so when I’m loading the cache I can easily discard those which are expired and this way free disk space. When creating your SKObject an expiry date is automatically assigned to it, but if you want to manually add it, you can simply specify it in the constructor like:

let object = SKObject(value: 'your value to store', forKey: 'your key under which the object will be stored', expiryDate: 'your expiry date')

By default SKObjects will never expire. You can change that option by changing the SKCache.shared.expiration. SKCache offers different possibilities for the expiry date:

/// Enum to indicate the live time of each time in the cache
///
/// - never: option to never expire the cache object
/// - everyDay: option to expire at the end of the day
/// - everyWeek: option to expiry after a week
/// - everyMonth: option to set the expiry date each month
/// - seconds: option to set the expiry after some secondspublic enum ExpiryDate {  
      case never  
      case everyDay  
      case everyWeek  
      case everyMonth  
      case seconds(TimeInterval)
.
.
.
}

Finally when I had my saving and loading methods for the cache, I needed a proper place where to call them. After a bit of analysing, the most appropriate place to load the cache was when an application starts. I implement SKCache.load() in the AppDelegate like:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

.
.
.

do {
try SKCache.load()
} catch {
print(error)
}

return true
}

Of course you can place the loading somewhere else and it will still works. Surrounding the method with try-catch block will ensure that if an error occurs you will be able to see it and analyse it.

Ok we have the loading of the object, and you might ask about saving the cache to the disk. Just implement SKCache.save() like:

func applicationDidEnterBackground(_ application: UIApplication) {

.
.
.

do {
try SKCache.save()
} catch {
print(error)
}
}

and you will save all of your objects to the disk space. Again by surrounding the method with try-catch block will ensure that if an error occurs you will be able to see it and analyse it. Implementing save() and load() methods will enable the disk cache for the library.

The functionality to save objects to the disk finally completed my cache library.

Currently SKCache is available only via Cocoapods . To install it, simply add the following line to your Podfile:

pod 'SKCache'

Any and all pull requests are welcome.. Check it out on GitHub .

责编内容by:Dev Labs (源链)。感谢您的支持!

您可能感兴趣的

iOS WKWebView 与 JS 交互实战技巧 最近公司需要针对 向日葵远程控制 和 花生壳动态域名解析服务客户端 做与HTML5交互的App,优点就是开发周期短,可随时更新内容。所以在这整理了...
解决Mac下check gdb is codesigned – see taskgated(8)问题... 文章目录 刚刚安装的GDB调试的时候会报 Starting program: /Users/wangxinguo/C/DataStruc...
iOS逆向学习~Logos指令 %hook %end %hook Classname %end 指定需要hook的类名 ,必须以%end结尾 例如 %hook...
Core Data Relationships While working on my latest project I have decided to write a tutorial about ...
iOS原生项目集成 Flutter 前不久,谷歌官方正式发布了Flutter的首个发布预览版(Release Preview 1),这标志着谷歌进入了Flutter正式版(1.0)发布前的最后阶段...