Create DownloadWithCacheManager, for when it’s a good idea to use a cache.

This commit is contained in:
Brent Simmons 2017-11-23 10:24:36 -08:00
parent ca4f4d408f
commit c9610f1f8e
1 changed files with 42 additions and 40 deletions

View File

@ -81,7 +81,7 @@ private final class WebCache {
cache.keys.forEach { (key) in
let cacheRecord = self[key]!
if shouldDelete(cacheRecord, cleanupInterval) {
self[key] = nil
cache[key] = nil
}
}
}
@ -106,45 +106,47 @@ private final class WebCache {
}
}
private var cache = WebCache()
private let timeToLive: TimeInterval = 5 * 60 // five minutes
private let cleanupInterval: TimeInterval = 20 * 60 // 20 minutes
// URLSessionConfiguration has a cache policy.
// But we dont know how it works, and the unimplemented parts spook us a bit.
// So we use a cache that works exactly as we want it to work.
private final class DownloadWithCacheManager {
static let shared = DownloadWithCacheManager()
private var cache = WebCache()
private static let timeToLive: TimeInterval = 5 * 60 // five minutes
private static let cleanupInterval: TimeInterval = 20 * 60 // 20 minutes
func download(_ url: URL, _ callback: @escaping OneShotDownloadCallback) {
cache.cleanup(DownloadWithCacheManager.cleanupInterval)
let cacheRecord: WebCacheRecord? = cache[url]
if let cacheRecord = cacheRecord, !cacheRecord.isExpired(DownloadWithCacheManager.timeToLive) {
callback(cacheRecord.data, cacheRecord.response, nil)
return
}
download(url) { (data, response, error) in
if let _ = error, let cacheRecord = cacheRecord {
// In the case where a cache record has expired, but the download returned an error, we use the cache record anyway. By design.
callback(cacheRecord.data, cacheRecord.response, nil)
return
}
if let data = data, let response = response, response.statusIsOK, error == nil {
let cacheRecord = WebCacheRecord(url: url, dateDownloaded: Date(), data: data, response: response)
self.cache[url] = cacheRecord
}
callback(data, response, error)
}
}
}
public func downloadUsingCache(_ url: URL, _ callback: @escaping OneShotDownloadCallback) {
// In the case where a cache record has expired, but the download returned an error,
// we use the cache record anyway. By design.
// Only OK status responses are cached.
cache.cleanup(cleanupInterval)
let cacheRecord: WebCacheRecord? = cache[url]
func callbackWith(_ cacheRecord: WebCacheRecord) {
callback(cacheRecord.data, cacheRecord.response, nil)
}
if let cacheRecord = cacheRecord, !cacheRecord.isExpired(timeToLive) {
callbackWith(cacheRecord)
return
}
download(url) { (data, response, error) in
if let error = error {
if let cacheRecord = cacheRecord {
callbackWith(cacheRecord)
return
}
callback(data, response, error)
return
}
if let data = data, let response = response, response.statusIsOK, error == nil {
let cacheRecord = WebCacheRecord(url: url, dateDownloaded: Date(), data: data, response: response)
cache[url] = cacheRecord
}
callback(data, response, error)
}
DownloadWithCacheManager.shared.download(url, callback)
}