diff --git a/Sources/OneWay/Store.swift b/Sources/OneWay/Store.swift index cd6842b..a275683 100644 --- a/Sources/OneWay/Store.swift +++ b/Sources/OneWay/Store.swift @@ -44,7 +44,7 @@ where R.Action: Sendable, R.State: Sendable & Equatable { private var actionQueue: [Action] = [] private var bindingTask: Task? private var tasks: [TaskID: Task] = [:] - private var cancellables: [_EffectID: Set] = [:] + private var cancellables: [EffectIDWrapper: Set] = [:] /// Initializes a store from a reducer and an initial state. /// @@ -75,10 +75,11 @@ where R.Action: Sendable, R.State: Sendable & Equatable { public func send(_ action: Action) async { actionQueue.append(action) guard !isProcessing else { return } - isProcessing = true - while !actionQueue.isEmpty { - let action = actionQueue.removeFirst() + await Task.yield() + let count = actionQueue.count + for index in Int.zero ..< count { + let action = actionQueue[index] let taskID = TaskID() let effect = reducer.reduce(state: &state, action: action) let task = Task { [weak self, taskID] in @@ -94,19 +95,20 @@ where R.Action: Sendable, R.State: Sendable & Equatable { switch effect.method { case let .register(id, cancelInFlight): if cancelInFlight { - let taskIDs = cancellables[_EffectID(id), default: []] + let taskIDs = cancellables[EffectIDWrapper(id), default: []] taskIDs.forEach { removeTask($0) } } - cancellables[_EffectID(id), default: []].insert(taskID) + cancellables[EffectIDWrapper(id), default: []].insert(taskID) case .cancel(let id): - let taskIDs = cancellables[_EffectID(id), default: []] + let taskIDs = cancellables[EffectIDWrapper(id), default: []] taskIDs.forEach { removeTask($0) } case .none: break } } + actionQueue = [] isProcessing = false } @@ -140,7 +142,7 @@ where R.Action: Sendable, R.State: Sendable & Equatable { } } -private struct _EffectID: Hashable, @unchecked Sendable { +private struct EffectIDWrapper: Hashable, @unchecked Sendable { private let id: AnyHashable fileprivate init(_ id: some Hashable & Sendable) { diff --git a/Tests/OneWayTests/StoreTests.swift b/Tests/OneWayTests/StoreTests.swift index b5d5adb..4e22c26 100644 --- a/Tests/OneWayTests/StoreTests.swift +++ b/Tests/OneWayTests/StoreTests.swift @@ -68,7 +68,7 @@ final class StoreTests: XCTestCase { } func test_threadSafeSendingActions() async { - let iterations: Int = 10_000 + let iterations: Int = 100_000 let sut = sut! DispatchQueue.concurrentPerform( iterations: iterations / 2,