diff --git a/Sources/ComposableArchitecture/Core.swift b/Sources/ComposableArchitecture/Core.swift index f853848df963..b50119322fb0 100644 --- a/Sources/ComposableArchitecture/Core.swift +++ b/Sources/ComposableArchitecture/Core.swift @@ -205,7 +205,7 @@ final class ScopedCore: Core { let stateKeyPath: KeyPath let actionKeyPath: CaseKeyPath #if DEBUG - let isInPerceptionTracking = _PerceptionLocals.isInPerceptionTracking + let initializedInPerceptionTracking = _isInPerceptionTracking #endif init( base: Base, @@ -220,7 +220,9 @@ final class ScopedCore: Core { @inline(__always) var state: State { #if DEBUG - return _PerceptionLocals.$skipPerceptionChecking.withValue(isInPerceptionTracking) { + return _PerceptionLocals.$skipPerceptionChecking.withValue( + initializedInPerceptionTracking || _isInPerceptionTracking + ) { base.state[keyPath: stateKeyPath] } #else diff --git a/Sources/ComposableArchitecture/Observation/IdentifiedArray+Observation.swift b/Sources/ComposableArchitecture/Observation/IdentifiedArray+Observation.swift index eafff521fe4c..70a39c3baa24 100644 --- a/Sources/ComposableArchitecture/Observation/IdentifiedArray+Observation.swift +++ b/Sources/ComposableArchitecture/Observation/IdentifiedArray+Observation.swift @@ -92,7 +92,7 @@ extension Store where State: ObservableState { public struct _StoreCollection: RandomAccessCollection { private let store: Store, IdentifiedAction> private let data: IdentifiedArray - private let isInPerceptionTracking = _isInPerceptionTracking + private let initializedInPerceptionTracking = _isInPerceptionTracking #if swift(<5.10) @MainActor(unsafe) @@ -146,7 +146,9 @@ public struct _StoreCollection: RandomAc return child } #if DEBUG - return _PerceptionLocals.$isInPerceptionTracking.withValue(self.isInPerceptionTracking) { + return _PerceptionLocals.$isInPerceptionTracking.withValue( + self.initializedInPerceptionTracking || _isInPerceptionTracking + ) { child } #else diff --git a/Sources/ComposableArchitecture/Store.swift b/Sources/ComposableArchitecture/Store.swift index 9e15b0060418..da3031689978 100644 --- a/Sources/ComposableArchitecture/Store.swift +++ b/Sources/ComposableArchitecture/Store.swift @@ -1,4 +1,5 @@ import Combine +import CombineSchedulers import Foundation import SwiftUI @@ -336,7 +337,7 @@ public final class Store: _Store { func subscribeToDidSet(_ type: T.Type) -> AnyCancellable { return core.didSet .prefix { [weak self] _ in self?.core.isInvalid == false } - .compactMap { [weak self] in (self?.currentState as? T)?._$id } + .compactMap { [weak self] in (self?.withState(\.self) as? T)?._$id } .removeDuplicates() .dropFirst() .sink { [weak self, weak parent] _ in @@ -375,7 +376,7 @@ public final class Store: _Store { public var publisher: StorePublisher { StorePublisher( store: self, - upstream: self.core.didSet.map { self.currentState } + upstream: self.core.didSet.receive(on: UIScheduler.shared).map { self.withState(\.self) } ) } diff --git a/Tests/ComposableArchitectureTests/StoreTests.swift b/Tests/ComposableArchitectureTests/StoreTests.swift index 3df6642aed52..efd15ed960c4 100644 --- a/Tests/ComposableArchitectureTests/StoreTests.swift +++ b/Tests/ComposableArchitectureTests/StoreTests.swift @@ -1175,6 +1175,14 @@ final class StoreTests: BaseTCATestCase { XCTAssertNil(weakStore) } + @MainActor + func testPublisherAsyncSequence() async { + if #available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) { + let store = Store(initialState: ()) {} + _ = await store.publisher.values.first { @Sendable _ in true } + } + } + @MainActor func testSharedMutation() async { XCTTODO(