From b04876185ddc36010dde97a96007dc10616dafdd Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Wed, 13 Dec 2017 21:18:20 -0800 Subject: [PATCH] =?UTF-8?q?Clean=20up=20DownloadWithCacheManager=E2=80=99s?= =?UTF-8?q?=20cache=20at=20most=20every=20five=20minutes=20=E2=80=94=C2=A0?= =?UTF-8?q?it=E2=80=99s=20very=20expensive=20to=20do=20it=20on=20every=20r?= =?UTF-8?q?equest.=20This=20dramatically=20helps=20sidebar=20scrolling=20p?= =?UTF-8?q?erformance=20when=20you=20have=20a=20couple=20thousand=20feeds?= =?UTF-8?q?=20all=20trying=20to=20get=20their=20favicons.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Frameworks/RSWeb/RSWeb/OneShotDownload.swift | 30 ++++++++------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/Frameworks/RSWeb/RSWeb/OneShotDownload.swift b/Frameworks/RSWeb/RSWeb/OneShotDownload.swift index fd3beed24..455e94d65 100755 --- a/Frameworks/RSWeb/RSWeb/OneShotDownload.swift +++ b/Frameworks/RSWeb/RSWeb/OneShotDownload.swift @@ -65,11 +65,6 @@ private struct WebCacheRecord { let dateDownloaded: Date let data: Data let response: URLResponse - - func isExpired(_ timeToLive: TimeInterval) -> Bool { - - return Date().timeIntervalSince(dateDownloaded) > timeToLive - } } private final class WebCache { @@ -77,18 +72,19 @@ private final class WebCache { private var cache = [URL: WebCacheRecord]() func cleanup(_ cleanupInterval: TimeInterval) { - + + let cutoffDate = Date(timeInterval: -cleanupInterval, since: Date()) cache.keys.forEach { (key) in let cacheRecord = self[key]! - if shouldDelete(cacheRecord, cleanupInterval) { + if shouldDelete(cacheRecord, cutoffDate) { cache[key] = nil } } } - private func shouldDelete(_ cacheRecord: WebCacheRecord, _ cleanupInterval: TimeInterval) -> Bool { + private func shouldDelete(_ cacheRecord: WebCacheRecord, _ cutoffDate: Date) -> Bool { - return Date().timeIntervalSince(cacheRecord.dateDownloaded) > cleanupInterval + return cacheRecord.dateDownloaded < cutoffDate } subscript(_ url: URL) -> WebCacheRecord? { @@ -115,26 +111,24 @@ private final class DownloadWithCacheManager { static let shared = DownloadWithCacheManager() private var cache = WebCache() private static let timeToLive: TimeInterval = 10 * 60 // 10 minutes - private static let cleanupInterval: TimeInterval = 30 * 60 // 30 minutes + private static let cleanupInterval: TimeInterval = 5 * 60 // clean up the cache at most every 5 minutes + private var lastCleanupDate = Date() func download(_ url: URL, _ callback: @escaping OneShotDownloadCallback) { - cache.cleanup(DownloadWithCacheManager.cleanupInterval) + if lastCleanupDate.timeIntervalSinceNow < -(5 * 60) { + lastCleanupDate = Date() + cache.cleanup(DownloadWithCacheManager.timeToLive) + } let cacheRecord: WebCacheRecord? = cache[url] - if let cacheRecord = cacheRecord, !cacheRecord.isExpired(DownloadWithCacheManager.timeToLive) { + if let cacheRecord = cacheRecord { callback(cacheRecord.data, cacheRecord.response, nil) return } OneShotDownloadManager.shared.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