Skip to content

Commit 3e0b086

Browse files
committed
Fixes initial value of spices
1 parent 0a35743 commit 3e0b086

File tree

6 files changed

+34
-28
lines changed

6 files changed

+34
-28
lines changed

Diff for: Sources/Spices/Internal/Preparable.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
protocol Preparable {
2-
func prepare(propertyName: String, ownedBy spiceStore: some SpiceStore)
2+
func prepare(propertyName: String, ownedBy spiceStore: any SpiceStore)
33
}

Diff for: Sources/Spices/Internal/Storage/AnyStorage.swift

+11
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ final class AnyStorage<Value>: ObservableObject {
1212
}
1313
}
1414

15+
private let read: () -> Value
1516
private let write: (Value) -> Void
17+
private let prepare: (String, any SpiceStore) -> Void
1618
private var cancellables: Set<AnyCancellable> = []
1719
@Published private var backingValue: Value
1820

@@ -37,6 +39,15 @@ final class AnyStorage<Value>: ObservableObject {
3739
private init<S: Storage>(storage: S) where S.Value == Value {
3840
publisher = storage.publisher
3941
backingValue = storage.value
42+
read = { storage.value }
4043
write = { storage.value = $0 }
44+
prepare = { storage.prepare(propertyName: $0, ownedBy: $1) }
45+
}
46+
}
47+
48+
extension AnyStorage: Preparable {
49+
func prepare(propertyName: String, ownedBy spiceStore: any SpiceStore) {
50+
prepare(propertyName, spiceStore)
51+
backingValue = read()
4152
}
4253
}

Diff for: Sources/Spices/Internal/Storage/Storage.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Combine
22

3-
protocol Storage: AnyObject {
3+
protocol Storage: AnyObject, Preparable {
44
associatedtype Value
55
var value: Value { get set }
66
var publisher: AnyPublisher<Value, Never> { get }

Diff for: Sources/Spices/Internal/Storage/ThrowingStorage.swift

+2
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,6 @@ final class ThrowingStorage<Value>: Storage {
2222
self.setterMessage = setterMessage
2323
self.publisher = passthroughSubject.eraseToAnyPublisher()
2424
}
25+
26+
func prepare(propertyName: String, ownedBy spiceStore: any SpiceStore) {}
2527
}

Diff for: Sources/Spices/Internal/Storage/UserDefaultsStorage.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ private extension UserDefaultsStorage {
103103
}
104104

105105
extension UserDefaultsStorage: Preparable {
106-
func prepare(propertyName: String, ownedBy spiceStore: some SpiceStore) {
106+
func prepare(propertyName: String, ownedBy spiceStore: any SpiceStore) {
107107
self.propertyName = propertyName
108108
self.spiceStore = spiceStore
109109
if let read {

Diff for: Sources/Spices/Spice.swift

+18-25
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,7 @@ import Foundation
7979
let name: Name
8080
let menuItem: any MenuItem
8181

82-
private let initialValue: Value
8382
private let storage: AnyStorage<Value>
84-
private let userDefaultsStorage: UserDefaultsStorage<Value>?
8583

8684
/// Initializes a `Spice` property wrapper for a boolean setting.
8785
/// - Parameters:
@@ -95,11 +93,8 @@ import Foundation
9593
name: String? = nil,
9694
requiresRestart: Bool = false
9795
) where Value == Bool {
98-
self.initialValue = wrappedValue
9996
self.name = Name(name)
100-
let userDefaultsStorage = UserDefaultsStorage(default: wrappedValue, key: key)
101-
self.userDefaultsStorage = userDefaultsStorage
102-
self.storage = AnyStorage(userDefaultsStorage)
97+
self.storage = AnyStorage(UserDefaultsStorage(default: wrappedValue, key: key))
10398
self.menuItem = ToggleMenuItem(
10499
name: self.name,
105100
requiresRestart: requiresRestart,
@@ -119,11 +114,8 @@ import Foundation
119114
name: String? = nil,
120115
requiresRestart: Bool = false
121116
) where Value: RawRepresentable & CaseIterable {
122-
self.initialValue = wrappedValue
123117
self.name = Name(name)
124-
let userDefaultsStorage = UserDefaultsStorage(default: wrappedValue, key: key)
125-
self.userDefaultsStorage = userDefaultsStorage
126-
self.storage = AnyStorage(userDefaultsStorage)
118+
self.storage = AnyStorage(UserDefaultsStorage(default: wrappedValue, key: key))
127119
self.menuItem = PickerMenuItem(
128120
name: self.name,
129121
storage: self.storage,
@@ -141,13 +133,11 @@ import Foundation
141133
name: String? = nil,
142134
requiresRestart: Bool = false
143135
) where Value == ButtonHandler {
144-
self.initialValue = wrappedValue
145136
self.name = Name(name)
146137
self.storage = AnyStorage(ThrowingStorage(
147138
default: wrappedValue,
148139
setterMessage: "Cannot set closure of Spices button."
149140
))
150-
self.userDefaultsStorage = nil
151141
self.menuItem = ButtonMenuItem(
152142
name: self.name,
153143
requiresRestart: requiresRestart,
@@ -165,13 +155,11 @@ import Foundation
165155
name: String? = nil,
166156
requiresRestart: Bool = false
167157
) where Value == AsyncButtonHandler {
168-
self.initialValue = wrappedValue
169158
self.name = Name(name)
170159
self.storage = AnyStorage(ThrowingStorage(
171160
default: wrappedValue,
172161
setterMessage: "Cannot set closure of Spices button."
173162
))
174-
self.userDefaultsStorage = nil
175163
self.menuItem = AsyncButtonMenuItem(
176164
name: self.name,
177165
requiresRestart: requiresRestart,
@@ -184,13 +172,11 @@ import Foundation
184172
/// - wrappedValue: The spice store to creaete hierarchial navigation to.
185173
/// - name: The display name of the spice store. Defaults to a formatted version of the property name.
186174
public init(wrappedValue: Value, name: String? = nil) where Value: SpiceStore {
187-
self.initialValue = wrappedValue
188175
self.name = Name(name)
189176
self.storage = AnyStorage(ThrowingStorage(
190177
default: wrappedValue,
191178
setterMessage: "Cannot assign new reference to nested spice store."
192179
))
193-
self.userDefaultsStorage = nil
194180
self.menuItem = ChildSpiceStoreMenuItem(name: self.name, spiceStore: wrappedValue)
195181
}
196182

@@ -214,17 +200,24 @@ import Foundation
214200
}
215201

216202
extension Spice: Preparable {
217-
func prepare(propertyName: String, ownedBy spiceStore: some SpiceStore) {
203+
func prepare(propertyName: String, ownedBy spiceStore: any SpiceStore) {
218204
name.rawValue = propertyName.camelCaseToNaturalText()
219-
userDefaultsStorage?.prepare(propertyName: propertyName, ownedBy: spiceStore)
220-
if let childSpiceStore = initialValue as? any SpiceStore {
221-
if childSpiceStore.parent != nil {
222-
fatalError("A child spice store can only be referenced from one parent.")
223-
}
224-
childSpiceStore.parent = spiceStore
225-
childSpiceStore.propertyName = propertyName
226-
childSpiceStore.prepareIfNeeded()
205+
storage.prepare(propertyName: propertyName, ownedBy: spiceStore)
206+
prepareChildSpiceStoreIfNeeded(propertyName: propertyName, parent: spiceStore)
207+
}
208+
}
209+
210+
private extension Spice {
211+
private func prepareChildSpiceStoreIfNeeded(propertyName: String, parent: any SpiceStore) {
212+
guard let childSpiceStore = storage.value as? any SpiceStore else {
213+
return
214+
}
215+
guard childSpiceStore.parent == nil else {
216+
fatalError("A child spice store can only be referenced from one parent.")
227217
}
218+
childSpiceStore.parent = parent
219+
childSpiceStore.propertyName = propertyName
220+
childSpiceStore.prepareIfNeeded()
228221
}
229222
}
230223

0 commit comments

Comments
 (0)