From e956ee71d7298c4d9186a9020c4eb71f6ec484cf Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Fri, 4 Apr 2025 10:22:11 -0700 Subject: [PATCH 1/2] Cut off firehose when core is invalid. --- .../iOS 17/ObservableSharedStateTestCase.swift | 12 ++++++------ Sources/ComposableArchitecture/Store.swift | 9 +++++++-- .../StorePerceptionTests.swift | 1 + 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Examples/Integration/Integration/iOS 17/ObservableSharedStateTestCase.swift b/Examples/Integration/Integration/iOS 17/ObservableSharedStateTestCase.swift index e4f3a1f27b44..6fbe00213323 100644 --- a/Examples/Integration/Integration/iOS 17/ObservableSharedStateTestCase.swift +++ b/Examples/Integration/Integration/iOS 17/ObservableSharedStateTestCase.swift @@ -112,12 +112,12 @@ private struct Feature { defaults.removeObject(forKey: "isOn") } case .resetButtonTapped: - state.isAppStorageOn1 = false - state.isAppStorageOn2 = false - state.fileStorage1.isOn = false - state.fileStorage2.isOn = false - state.isInMemoryOn1 = false - state.isInMemoryOn2 = false + state.$isAppStorageOn1.withLock { $0 = false } + state.$isAppStorageOn2.withLock { $0 = false } + state.$fileStorage1.withLock { $0.isOn = false } + state.$fileStorage2.withLock { $0.isOn = false } + state.$isInMemoryOn1.withLock { $0 = false } + state.$isInMemoryOn2.withLock { $0 = false } return .none case .writeToFileStorageButtonTapped: return .run { [isOn = state.fileStorage1.isOn] _ in diff --git a/Sources/ComposableArchitecture/Store.swift b/Sources/ComposableArchitecture/Store.swift index 590686fe8184..9a987a8731ae 100644 --- a/Sources/ComposableArchitecture/Store.swift +++ b/Sources/ComposableArchitecture/Store.swift @@ -371,8 +371,13 @@ public final class Store { if let stateType = State.self as? any ObservableState.Type { func subscribeToDidSet(_ type: T.Type) -> AnyCancellable { - core.didSet - .compactMap { [weak self] in (self?.currentState as? T)?._$id } + return core.didSet + .prefix { [weak self] _ in + self?.core.isInvalid != true + } + .compactMap { [weak self] in + (self?.currentState as? T)?._$id + } .removeDuplicates() .dropFirst() .sink { [weak self] _ in diff --git a/Tests/ComposableArchitectureTests/StorePerceptionTests.swift b/Tests/ComposableArchitectureTests/StorePerceptionTests.swift index 9cc3081eeb61..bffa28d06251 100644 --- a/Tests/ComposableArchitectureTests/StorePerceptionTests.swift +++ b/Tests/ComposableArchitectureTests/StorePerceptionTests.swift @@ -32,6 +32,7 @@ final class StorePerceptionTests: BaseTCATestCase { } @MainActor + @available(*, deprecated) func testPerceptionCheck_AccessStateWithoutTracking() { @MainActor struct FeatureView: View { From fe9c4bbb4cf8fccd590ef10d0aea6a8d8f24dbbb Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Fri, 4 Apr 2025 10:36:37 -0700 Subject: [PATCH 2/2] wip --- Sources/ComposableArchitecture/Store.swift | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Sources/ComposableArchitecture/Store.swift b/Sources/ComposableArchitecture/Store.swift index 9a987a8731ae..542869bd918d 100644 --- a/Sources/ComposableArchitecture/Store.swift +++ b/Sources/ComposableArchitecture/Store.swift @@ -372,12 +372,8 @@ public final class Store { if let stateType = State.self as? any ObservableState.Type { func subscribeToDidSet(_ type: T.Type) -> AnyCancellable { return core.didSet - .prefix { [weak self] _ in - self?.core.isInvalid != true - } - .compactMap { [weak self] in - (self?.currentState as? T)?._$id - } + .prefix { [weak self] _ in self?.core.isInvalid != true } + .compactMap { [weak self] in (self?.currentState as? T)?._$id } .removeDuplicates() .dropFirst() .sink { [weak self] _ in