@@ -98,8 +98,14 @@ import SwiftUI
98
98
#else
99
99
@preconcurrency @MainActor
100
100
#endif
101
- public final class Store < State, Action> {
101
+ public final class Store < State, Action> : _Store {
102
102
var children : [ ScopeID < State , Action > : AnyObject ] = [ : ]
103
+ private weak var parent : ( any _Store ) ?
104
+ private let scopeID : AnyHashable ?
105
+
106
+ func removeChild( scopeID: AnyHashable ) {
107
+ children [ scopeID as! ScopeID < State , Action > ] = nil
108
+ }
103
109
104
110
let core : any Core < State , Action >
105
111
@_spi ( Internals) public var effectCancellables : [ UUID : AnyCancellable ] { core. effectCancellables }
@@ -139,6 +145,7 @@ public final class Store<State, Action> {
139
145
140
146
init ( ) {
141
147
self . core = InvalidCore ( )
148
+ self . scopeID = nil
142
149
}
143
150
144
151
deinit {
@@ -266,7 +273,7 @@ public final class Store<State, Action> {
266
273
let id,
267
274
let child = children [ id] as? Store < ChildState , ChildAction >
268
275
else {
269
- let child = Store < ChildState , ChildAction > ( core: childCore ( ) )
276
+ let child = Store < ChildState , ChildAction > ( core: childCore ( ) , scopeID : id , parent : self )
270
277
if core. canStoreCacheChildren, let id {
271
278
children [ id] = child
272
279
}
@@ -313,18 +320,24 @@ public final class Store<State, Action> {
313
320
core. send ( action)
314
321
}
315
322
316
- private init ( core: some Core < State , Action > ) {
323
+ private init ( core: some Core < State , Action > , scopeID : AnyHashable ? , parent : ( any _Store ) ? ) {
317
324
defer { Logger . shared. log ( " \( storeTypeName ( of: self ) ) .init " ) }
318
325
self . core = core
326
+ self . parent = parent
327
+ self . scopeID = scopeID
319
328
320
329
if let stateType = State . self as? any ObservableState . Type {
321
330
func subscribeToDidSet< T: ObservableState > ( _ type: T . Type ) -> AnyCancellable {
322
331
return core. didSet
323
- . prefix { [ weak self] _ in self ? . core. isInvalid != true }
332
+ . prefix { [ weak self] _ in self ? . core. isInvalid == false }
324
333
. compactMap { [ weak self] in ( self ? . currentState as? T ) ? . _$id }
325
334
. removeDuplicates ( )
326
335
. dropFirst ( )
327
336
. sink { [ weak self] _ in
337
+ guard let scopeID = self ? . scopeID
338
+ else { return }
339
+ parent? . removeChild ( scopeID: scopeID)
340
+ } receiveValue: { [ weak self] _ in
328
341
guard let self else { return }
329
342
self . _$observationRegistrar. withMutation ( of: self , keyPath: \. currentState) { }
330
343
}
@@ -337,7 +350,11 @@ public final class Store<State, Action> {
337
350
initialState: R . State ,
338
351
reducer: R
339
352
) {
340
- self . init ( core: RootCore ( initialState: initialState, reducer: reducer) )
353
+ self . init (
354
+ core: RootCore ( initialState: initialState, reducer: reducer) ,
355
+ scopeID: nil ,
356
+ parent: nil
357
+ )
341
358
}
342
359
343
360
/// A publisher that emits when state changes.
@@ -565,3 +582,8 @@ let _isStorePerceptionCheckingEnabled: Bool = {
565
582
@available ( iOS 17 , macOS 14 , tvOS 17 , watchOS 10 , * )
566
583
extension Store : Observable { }
567
584
#endif
585
+
586
+ @MainActor
587
+ private protocol _Store : AnyObject {
588
+ func removeChild( scopeID: AnyHashable )
589
+ }
0 commit comments