Skip to content

Commit

Permalink
Adding a layer of caching to skip JSON decoding when accessing a Stor…
Browse files Browse the repository at this point in the history
…edValue
  • Loading branch information
mergesort committed Apr 10, 2024
1 parent 4b33c28 commit 221d9f8
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 2 deletions.
25 changes: 25 additions & 0 deletions Sources/Boutique/CachedValue.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Foundation

/// `CachedValue` exists internally for the purpose of creating a reference value, preventing the need
/// to create a `JSONDecoder` and invoke a decode step every time we need to access a `StoredValue` externally.
internal final class CachedValue<Item: Codable> {
private var cachedValue: Item?
public var retrieveValue: () -> Item

init(retrieveValue: @escaping () -> Item) {
self.retrieveValue = retrieveValue
self.cachedValue = self.retrieveValue()
}

func set(_ value: Item) {
self.cachedValue = value
}

var wrappedValue: Item? {
if let cachedValue {
cachedValue
} else {
self.retrieveValue()
}
}
}
1 change: 0 additions & 1 deletion Sources/Boutique/StoredValue+Binding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ public extension StoredValue {
}
}


public extension SecurelyStoredValue {
/// A convenient way to create a `Binding` from a `SecurelyStoredValue`.
///
Expand Down
10 changes: 9 additions & 1 deletion Sources/Boutique/StoredValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,24 @@ public struct StoredValue<Item: Codable> {
private let userDefaults: UserDefaults
private let itemSubject: CurrentValueSubject<Item, Never>

private var cachedValue: CachedValue<Item>

public init(wrappedValue: Item, key: String, storage userDefaults: UserDefaults = UserDefaults.standard) {
self.key = key
self.defaultValue = wrappedValue
self.userDefaults = userDefaults

let initialValue = Self.storedValue(forKey: key, userDefaults: userDefaults, defaultValue: defaultValue)
self.itemSubject = CurrentValueSubject(initialValue)

self.cachedValue = CachedValue(retrieveValue: {
Self.storedValue(forKey: key, userDefaults: userDefaults, defaultValue: initialValue)
})
}

/// The currently stored value
public var wrappedValue: Item {
Self.storedValue(forKey: self.key, userDefaults: self.userDefaults, defaultValue: self.defaultValue)
self.cachedValue.retrieveValue()
}

/// A ``StoredValue`` which exposes ``set(_:)`` and ``reset()`` functions alongside a ``publisher``.
Expand Down Expand Up @@ -94,6 +100,7 @@ public struct StoredValue<Item: Codable> {
let boxedValue = BoxedValue(value: value)
if let data = try? JSONCoders.encoder.encode(boxedValue) {
self.userDefaults.set(data, forKey: self.key)
self.cachedValue.set(value)
self.itemSubject.send(value)
}
}
Expand Down Expand Up @@ -123,6 +130,7 @@ public struct StoredValue<Item: Codable> {
let boxedValue = BoxedValue(value: self.defaultValue)
if let data = try? JSONCoders.encoder.encode(boxedValue) {
self.userDefaults.set(data, forKey: self.key)
self.cachedValue.set(self.defaultValue)
self.itemSubject.send(self.defaultValue)
}
}
Expand Down

0 comments on commit 221d9f8

Please sign in to comment.