Skip to content

Commit aae2212

Browse files
authored
Refactor StoreContext (#113)
1 parent 0da7155 commit aae2212

16 files changed

+146
-181
lines changed

Sources/Atoms/AtomRoot.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ private extension AtomRoot {
173173
content.environment(
174174
\.store,
175175
StoreContext(
176-
state.store,
176+
store: state.store,
177177
scopeKey: ScopeKey(token: state.token),
178178
inheritedScopeKeys: [:],
179179
observers: observers,
@@ -203,7 +203,7 @@ private extension AtomRoot {
203203
content.environment(
204204
\.store,
205205
StoreContext(
206-
store,
206+
store: store,
207207
scopeKey: ScopeKey(token: state.token),
208208
inheritedScopeKeys: [:],
209209
observers: observers,

Sources/Atoms/AtomScope.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ private extension AtomScope {
172172
var body: some View {
173173
content.environment(
174174
\.store,
175-
environmentStore.scoped(
175+
environmentStore?.scoped(
176176
scopeKey: ScopeKey(token: state.token),
177177
scopeID: id,
178178
observers: observers,

Sources/Atoms/Context/AtomTestContext.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ internal extension AtomTestContext {
439439
@usableFromInline
440440
var _store: StoreContext {
441441
StoreContext(
442-
_state.store,
442+
store: _state.store,
443443
scopeKey: ScopeKey(token: _state.token),
444444
inheritedScopeKeys: [:],
445445
observers: [],
Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,14 @@
11
import SwiftUI
22

33
internal extension EnvironmentValues {
4-
var store: StoreContext {
4+
var store: StoreContext? {
55
get { self[StoreEnvironmentKey.self] }
66
set { self[StoreEnvironmentKey.self] = newValue }
77
}
88
}
99

1010
private struct StoreEnvironmentKey: EnvironmentKey {
11-
static var defaultValue: StoreContext {
12-
StoreContext(
13-
nil,
14-
scopeKey: ScopeKey(token: ScopeKey.Token()),
15-
inheritedScopeKeys: [:],
16-
observers: [],
17-
scopedObservers: [],
18-
overrides: [:],
19-
scopedOverrides: [:],
20-
enablesAssertion: true
21-
)
11+
static var defaultValue: StoreContext? {
12+
nil
2213
}
2314
}

Sources/Atoms/Core/StoreContext.swift

Lines changed: 10 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,44 @@ import Foundation
33
@usableFromInline
44
@MainActor
55
internal struct StoreContext {
6-
private weak var weakStore: AtomStore?
6+
private let store: AtomStore
77
private let scopeKey: ScopeKey
88
private let inheritedScopeKeys: [ScopeID: ScopeKey]
99
private let observers: [Observer]
1010
private let scopedObservers: [Observer]
1111
private let overrides: [OverrideKey: any AtomOverrideProtocol]
1212
private let scopedOverrides: [OverrideKey: any AtomOverrideProtocol]
13-
private let enablesAssertion: Bool
1413

15-
nonisolated init(
16-
_ store: AtomStore?,
14+
init(
15+
store: AtomStore,
1716
scopeKey: ScopeKey,
1817
inheritedScopeKeys: [ScopeID: ScopeKey],
1918
observers: [Observer],
2019
scopedObservers: [Observer],
2120
overrides: [OverrideKey: any AtomOverrideProtocol],
22-
scopedOverrides: [OverrideKey: any AtomOverrideProtocol],
23-
enablesAssertion: Bool = false
21+
scopedOverrides: [OverrideKey: any AtomOverrideProtocol]
2422
) {
25-
self.weakStore = store
23+
self.store = store
2624
self.scopeKey = scopeKey
2725
self.inheritedScopeKeys = inheritedScopeKeys
2826
self.observers = observers
2927
self.scopedObservers = scopedObservers
3028
self.overrides = overrides
3129
self.scopedOverrides = scopedOverrides
32-
self.enablesAssertion = enablesAssertion
3330
}
3431

3532
func inherited(
3633
scopedObservers: [Observer],
3734
scopedOverrides: [OverrideKey: any AtomOverrideProtocol]
3835
) -> StoreContext {
3936
StoreContext(
40-
weakStore,
37+
store: store,
4138
scopeKey: scopeKey,
4239
inheritedScopeKeys: inheritedScopeKeys,
4340
observers: observers,
4441
scopedObservers: self.scopedObservers + scopedObservers,
4542
overrides: overrides,
46-
scopedOverrides: self.scopedOverrides.merging(scopedOverrides) { $1 },
47-
enablesAssertion: enablesAssertion
43+
scopedOverrides: self.scopedOverrides.merging(scopedOverrides) { $1 }
4844
)
4945
}
5046

@@ -55,14 +51,13 @@ internal struct StoreContext {
5551
overrides: [OverrideKey: any AtomOverrideProtocol]
5652
) -> StoreContext {
5753
StoreContext(
58-
weakStore,
54+
store: store,
5955
scopeKey: scopeKey,
6056
inheritedScopeKeys: mutating(inheritedScopeKeys) { $0[scopeID] = scopeKey },
6157
observers: self.observers,
6258
scopedObservers: observers,
6359
overrides: self.overrides,
64-
scopedOverrides: overrides,
65-
enablesAssertion: enablesAssertion
60+
scopedOverrides: overrides
6661
)
6762
}
6863

@@ -117,7 +112,6 @@ internal struct StoreContext {
117112
return read(atom)
118113
}
119114

120-
let store = getStore()
121115
let override = lookupOverride(of: atom)
122116
let scopeKey = lookupScopeKey(of: atom, isScopedOverriden: override?.isScoped ?? false)
123117
let key = AtomKey(atom, scopeKey: scopeKey)
@@ -137,7 +131,6 @@ internal struct StoreContext {
137131
requiresObjectUpdate: Bool,
138132
notifyUpdate: @escaping () -> Void
139133
) -> Node.Loader.Value {
140-
let store = getStore()
141134
let override = lookupOverride(of: atom)
142135
let scopeKey = lookupScopeKey(of: atom, isScopedOverriden: override?.isScoped ?? false)
143136
let key = AtomKey(atom, scopeKey: scopeKey)
@@ -276,9 +269,7 @@ internal struct StoreContext {
276269

277270
@usableFromInline
278271
func snapshot() -> Snapshot {
279-
let store = getStore()
280-
281-
return Snapshot(
272+
Snapshot(
282273
graph: store.graph,
283274
caches: store.state.caches,
284275
subscriptions: store.state.subscriptions
@@ -287,7 +278,6 @@ internal struct StoreContext {
287278

288279
@usableFromInline
289280
func restore(_ snapshot: Snapshot) {
290-
let store = getStore()
291281
let keys = ContiguousArray(snapshot.caches.keys)
292282
var obsoletedDependencies = [AtomKey: Set<AtomKey>]()
293283

@@ -328,7 +318,6 @@ internal struct StoreContext {
328318

329319
private extension StoreContext {
330320
func prepareForTransaction<Node: Atom>(of atom: Node, for key: AtomKey) -> AtomLoaderContext<Node.Loader.Value, Node.Loader.Coordinator> {
331-
let store = getStore()
332321
let state = getState(of: atom, for: key)
333322

334323
// Terminate the ongoing transaction first.
@@ -343,7 +332,6 @@ private extension StoreContext {
343332
}
344333

345334
let transaction = Transaction(key: key) {
346-
let store = getStore()
347335
let dependencies = store.graph.dependencies[key] ?? []
348336
let obsoletedDependencies = oldDependencies.subtracting(dependencies)
349337
let newDependencies = dependencies.subtracting(oldDependencies)
@@ -386,7 +374,6 @@ private extension StoreContext {
386374
cache: AtomCache<Node>,
387375
order: UpdateOrder
388376
) {
389-
let store = getStore()
390377
let oldValue = cache.value
391378

392379
if case .newValue = order {
@@ -446,8 +433,6 @@ private extension StoreContext {
446433
}
447434

448435
func unsubscribe<Keys: Sequence<AtomKey>>(_ keys: Keys, for subscriberKey: SubscriberKey) {
449-
let store = getStore()
450-
451436
for key in ContiguousArray(keys) {
452437
store.state.subscriptions[key]?.removeValue(forKey: subscriberKey)
453438
checkAndRelease(for: key)
@@ -458,8 +443,6 @@ private extension StoreContext {
458443

459444
@discardableResult
460445
func checkAndRelease(for key: AtomKey) -> Bool {
461-
let store = getStore()
462-
463446
// The condition under which an atom may be released are as follows:
464447
// 1. It's not marked as `KeepAlive`, is marked as `Scoped`, or is scoped by override.
465448
// 2. It has no downstream atoms.
@@ -479,7 +462,6 @@ private extension StoreContext {
479462

480463
func release(for key: AtomKey) {
481464
// Invalidate transactions, dependencies, and the atom state.
482-
let store = getStore()
483465
let dependencies = store.graph.dependencies.removeValue(forKey: key)
484466
let state = store.state.states.removeValue(forKey: key)
485467
store.graph.children.removeValue(forKey: key)
@@ -496,8 +478,6 @@ private extension StoreContext {
496478
}
497479

498480
func getState<Node: Atom>(of atom: Node, for key: AtomKey) -> AtomState<Node.Coordinator> {
499-
let store = getStore()
500-
501481
func makeState() -> AtomState<Node.Coordinator> {
502482
let coordinator = atom.makeCoordinator()
503483
let state = AtomState(coordinator: coordinator)
@@ -537,7 +517,6 @@ private extension StoreContext {
537517
for key: AtomKey,
538518
override: AtomOverride<Node>?
539519
) -> AtomCache<Node> {
540-
let store = getStore()
541520
let context = prepareForTransaction(of: atom, for: key)
542521
let value: Node.Loader.Value
543522

@@ -555,8 +534,6 @@ private extension StoreContext {
555534
}
556535

557536
func lookupCache<Node: Atom>(of atom: Node, for key: AtomKey) -> AtomCache<Node>? {
558-
let store = getStore()
559-
560537
guard let baseCache = store.state.caches[key] else {
561538
return nil
562539
}
@@ -637,64 +614,4 @@ private extension StoreContext {
637614
observer.onUpdate(snapshot)
638615
}
639616
}
640-
641-
func getStore() -> AtomStore {
642-
if let store = weakStore {
643-
return store
644-
}
645-
646-
assert(
647-
!enablesAssertion,
648-
"""
649-
[Atoms]
650-
There is no store provided on the current view tree.
651-
Make sure that this application has an `AtomRoot` as a root ancestor of any view.
652-
653-
```
654-
struct ExampleApp: App {
655-
var body: some Scene {
656-
WindowGroup {
657-
AtomRoot {
658-
ExampleView()
659-
}
660-
}
661-
}
662-
}
663-
```
664-
665-
If for some reason the view tree is formed that does not inherit from `EnvironmentValues`,
666-
consider using `AtomScope` to pass it.
667-
That happens when using SwiftUI view wrapped with `UIHostingController`.
668-
669-
```
670-
struct ExampleView: View {
671-
@ViewContext
672-
var context
673-
674-
var body: some View {
675-
UIViewWrappingView {
676-
AtomScope(inheriting: context) {
677-
WrappedView()
678-
}
679-
}
680-
}
681-
}
682-
```
683-
684-
The modal screen presented by the `.sheet` modifier or etc, inherits from the environment values,
685-
but only in iOS14, there is a bug where the environment values will be dismantled during it is
686-
dismissing. This also can be avoided by using `AtomScope` to explicitly inherit from it.
687-
688-
```
689-
.sheet(isPresented: ...) {
690-
AtomScope(inheriting: context) {
691-
ExampleView()
692-
}
693-
}
694-
```
695-
"""
696-
)
697-
698-
return AtomStore()
699-
}
700617
}

0 commit comments

Comments
 (0)