diff --git a/Sources/ObservableStore/ObservableStore.swift b/Sources/ObservableStore/ObservableStore.swift index ad6bbd3..999d27b 100644 --- a/Sources/ObservableStore/ObservableStore.swift +++ b/Sources/ObservableStore/ObservableStore.swift @@ -159,9 +159,9 @@ public struct Update { public protocol StoreProtocol { associatedtype Model: ModelProtocol - var state: Model { get } + @MainActor var state: Model { get } - func send(_ action: Model.Action) -> Void + @MainActor func send(_ action: Model.Action) -> Void } /// Store is a source of truth for a state. @@ -172,6 +172,7 @@ public protocol StoreProtocol { /// Store has a `@Published` `state` (typically a struct). /// All updates and effects to this state happen through actions /// sent to `store.send`. +@MainActor public final class Store: ObservableObject, StoreProtocol where Model: ModelProtocol { @@ -312,6 +313,7 @@ where Model: ModelProtocol } } +@MainActor public struct ViewStore: StoreProtocol { private var _send: (ViewModel.Action) -> Void public var state: ViewModel @@ -344,6 +346,7 @@ extension ViewStore { extension StoreProtocol { /// Create a viewStore from a StoreProtocol + @MainActor public func viewStore( get: (Self.Model) -> ViewModel, tag: @escaping (ViewModel.Action) -> Self.Model.Action @@ -387,6 +390,7 @@ extension Binding { } extension StoreProtocol { + @MainActor public func binding( get: @escaping (Self.Model) -> Value, tag: @escaping (Value) -> Self.Model.Action diff --git a/Tests/ObservableStoreTests/BindingTests.swift b/Tests/ObservableStoreTests/BindingTests.swift index 354f151..bd74a08 100644 --- a/Tests/ObservableStoreTests/BindingTests.swift +++ b/Tests/ObservableStoreTests/BindingTests.swift @@ -42,6 +42,7 @@ final class BindingTests: XCTestCase { } /// Test creating binding for an address + @MainActor func testBinding() throws { let store = Store( state: Model(), @@ -70,6 +71,7 @@ final class BindingTests: XCTestCase { } /// Test creating binding for an address + @MainActor func testBindingMethod() throws { let store = Store( state: Model(), diff --git a/Tests/ObservableStoreTests/ComponentMappingTests.swift b/Tests/ObservableStoreTests/ComponentMappingTests.swift index 9309902..3f95bf9 100644 --- a/Tests/ObservableStoreTests/ComponentMappingTests.swift +++ b/Tests/ObservableStoreTests/ComponentMappingTests.swift @@ -126,6 +126,7 @@ class ComponentMappingTests: XCTestCase { } } + @MainActor func testForward() throws { let store = Store( state: ParentModel(), @@ -150,6 +151,7 @@ class ComponentMappingTests: XCTestCase { ) } + @MainActor func testKeyedCursorUpdate() throws { let store = Store( state: ParentModel( @@ -185,6 +187,7 @@ class ComponentMappingTests: XCTestCase { ) } + @MainActor func testCursorUpdate() throws { let store = Store( state: ParentModel(), @@ -203,6 +206,7 @@ class ComponentMappingTests: XCTestCase { ) } + @MainActor func testKeyedCursorUpdateMissing() throws { let store = Store( state: ParentModel( diff --git a/Tests/ObservableStoreTests/ObservableStoreTests.swift b/Tests/ObservableStoreTests/ObservableStoreTests.swift index 2abaafe..a383092 100644 --- a/Tests/ObservableStoreTests/ObservableStoreTests.swift +++ b/Tests/ObservableStoreTests/ObservableStoreTests.swift @@ -86,6 +86,7 @@ final class ObservableStoreTests: XCTestCase { self.cancellables = Set() } + @MainActor func testStateAdvance() throws { let store = Store( state: AppModel(), @@ -100,6 +101,7 @@ final class ObservableStoreTests: XCTestCase { /// updates get removed from the cancellables array. /// /// Failure to remove immediately-completing fx would cause a memory leak. + @MainActor func testEmptyFxRemovedOnComplete() { let store = Store( state: AppModel(), @@ -133,6 +135,7 @@ final class ObservableStoreTests: XCTestCase { /// does not rely on an implementation detail of `Update` but instead /// tests this behavior directly, in case the implementation were to /// change somehow. + @MainActor func testEmptyFxThatCompleteImmiedatelyRemovedOnComplete() { let store = Store( state: AppModel(), @@ -155,6 +158,7 @@ final class ObservableStoreTests: XCTestCase { wait(for: [expectation], timeout: 0.1) } + @MainActor func testAsyncFxRemovedOnComplete() { let store = Store( state: AppModel(), @@ -176,6 +180,7 @@ final class ObservableStoreTests: XCTestCase { wait(for: [expectation], timeout: 0.5) } + @MainActor func testPublishedPropertyFires() throws { let store = Store( state: AppModel(), @@ -207,6 +212,7 @@ final class ObservableStoreTests: XCTestCase { wait(for: [expectation], timeout: 0.2) } + @MainActor func testStateOnlySetWhenNotEqual() { let store = Store( state: AppModel(), @@ -286,6 +292,7 @@ final class ObservableStoreTests: XCTestCase { var subtitle: String = "" } + @MainActor func testUpdateMergeFx() { let store = Store( state: TestUpdateMergeFxState(), @@ -318,6 +325,7 @@ final class ObservableStoreTests: XCTestCase { wait(for: [expectation], timeout: 0.2) } + @MainActor func testCreateInit() throws { let store = Store( create: { environment in @@ -343,6 +351,7 @@ final class ObservableStoreTests: XCTestCase { wait(for: [expectation], timeout: 0.1) } + @MainActor func testActionsPublisher() throws { let store = Store( state: AppModel(), diff --git a/Tests/ObservableStoreTests/UpdateActionsTests.swift b/Tests/ObservableStoreTests/UpdateActionsTests.swift index d53e111..c5942d9 100644 --- a/Tests/ObservableStoreTests/UpdateActionsTests.swift +++ b/Tests/ObservableStoreTests/UpdateActionsTests.swift @@ -69,6 +69,7 @@ class UpdateActionsTests: XCTestCase { } } + @MainActor func testUpdateActions() throws { let store = Store( state: TestModel(), diff --git a/Tests/ObservableStoreTests/ViewStoreTests.swift b/Tests/ObservableStoreTests/ViewStoreTests.swift index 9255356..6b0be9f 100644 --- a/Tests/ObservableStoreTests/ViewStoreTests.swift +++ b/Tests/ObservableStoreTests/ViewStoreTests.swift @@ -93,6 +93,7 @@ final class ViewStoreTests: XCTestCase { } /// Test creating binding for an address + @MainActor func testViewStore() throws { let store = Store( state: ParentModel(), @@ -118,6 +119,7 @@ final class ViewStoreTests: XCTestCase { } /// Test creating binding for an address + @MainActor func testViewStoreMethod() throws { let store = Store( state: ParentModel(),