From 602112d30f0a5515b358e1a7eadbffdf5eb1e32d Mon Sep 17 00:00:00 2001 From: Serhiy Mytrovtsiy Date: Thu, 18 Sep 2025 22:51:07 +0200 Subject: [PATCH] feat: added cache layer to the Store (#2696) --- Kit/plugins/Store.swift | 69 +++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/Kit/plugins/Store.swift b/Kit/plugins/Store.swift index 6cfb3f59..a5092236 100644 --- a/Kit/plugins/Store.swift +++ b/Kit/plugins/Store.swift @@ -14,58 +14,90 @@ import Cocoa public class Store { public static let shared = Store() private let defaults = UserDefaults.standard + private var cache: [String: Any] = [:] + private let cacheQueue = DispatchQueue(label: "eu.exelban.Stats.Store.cache", attributes: .concurrent) - public init() {} + public init() { + self.loadCache() + } + + private func loadCache() { + guard let bundleId = Bundle.main.bundleIdentifier, + let domain = self.defaults.persistentDomain(forName: bundleId) else { return } + self.cache = domain + } + + private func getValue(for key: String, type: T.Type) -> T? { + return self.cacheQueue.sync { + return self.cache[key] as? T + } + } + + private func setValue(_ value: Any?, for key: String) { + self.cacheQueue.async(flags: .barrier) { + self.cache[key] = value + } + + if let value = value { + self.defaults.set(value, forKey: key) + } else { + self.defaults.removeObject(forKey: key) + } + } public func exist(key: String) -> Bool { - return self.defaults.object(forKey: key) == nil ? false : true + return self.getValue(for: key, type: Any.self) != nil } public func remove(_ key: String) { - self.defaults.removeObject(forKey: key) + self.setValue(nil, for: key) } public func bool(key: String, defaultValue value: Bool) -> Bool { - return !self.exist(key: key) ? value : defaults.bool(forKey: key) + return self.getValue(for: key, type: Bool.self) ?? value } public func string(key: String, defaultValue value: String) -> String { - return (!self.exist(key: key) ? value : defaults.string(forKey: key))! + return self.getValue(for: key, type: String.self) ?? value } public func int(key: String, defaultValue value: Int) -> Int { - return (!self.exist(key: key) ? value : defaults.integer(forKey: key)) + return self.getValue(for: key, type: Int.self) ?? value } public func array(key: String, defaultValue value: [Any]) -> [Any] { - return (!self.exist(key: key) ? value : defaults.array(forKey: key)!) + return self.getValue(for: key, type: [Any].self) ?? value } public func data(key: String) -> Data? { - return defaults.data(forKey: key) + return self.getValue(for: key, type: Data.self) } public func set(key: String, value: Bool) { - self.defaults.set(value, forKey: key) + self.setValue(value, for: key) } public func set(key: String, value: String) { - self.defaults.set(value, forKey: key) + self.setValue(value, for: key) } public func set(key: String, value: Int) { - self.defaults.set(value, forKey: key) + self.setValue(value, for: key) } public func set(key: String, value: Data) { - self.defaults.set(value, forKey: key) + self.setValue(value, for: key) } public func set(key: String, value: [Any]) { - self.defaults.set(value, forKey: key) + self.setValue(value, for: key) } public func reset() { + self.cacheQueue.async(flags: .barrier) { + self.cache.removeAll() + } + self.defaults.dictionaryRepresentation().keys.forEach { key in self.defaults.removeObject(forKey: key) } @@ -81,17 +113,22 @@ public class Store { } public func `import`(from url: URL) { - guard let id = Bundle.main.bundleIdentifier, let dict = NSDictionary(contentsOf: url) as? [String: Any] else { return } + guard let id = Bundle.main.bundleIdentifier, + let dict = NSDictionary(contentsOf: url) as? [String: Any] else { return } - var importedDict = dict let keysToPreserve = ["telemetry_id", "access_token", "refresh_token"] + var importedDict = dict for key in keysToPreserve { - if let existingValue = self.defaults.string(forKey: key) { + if let existingValue = getValue(for: key, type: String.self) { importedDict[key] = existingValue } } + self.cacheQueue.async(flags: .barrier) { + self.cache = importedDict + } + self.defaults.setPersistentDomain(importedDict, forName: id) restartApp(self) }