Skip to content

Commit

Permalink
Isolate state and send to main actor
Browse files Browse the repository at this point in the history
Fixes #34
  • Loading branch information
gordonbrander committed Jul 7, 2023
1 parent 933547c commit 00ecc9d
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 2 deletions.
8 changes: 6 additions & 2 deletions Sources/ObservableStore/ObservableStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ public struct Update<Model: ModelProtocol> {
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.
Expand All @@ -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<Model>: ObservableObject, StoreProtocol
where Model: ModelProtocol
{
Expand Down Expand Up @@ -312,6 +313,7 @@ where Model: ModelProtocol
}
}

@MainActor
public struct ViewStore<ViewModel: ModelProtocol>: StoreProtocol {
private var _send: (ViewModel.Action) -> Void
public var state: ViewModel
Expand Down Expand Up @@ -344,6 +346,7 @@ extension ViewStore {

extension StoreProtocol {
/// Create a viewStore from a StoreProtocol
@MainActor
public func viewStore<ViewModel: ModelProtocol>(
get: (Self.Model) -> ViewModel,
tag: @escaping (ViewModel.Action) -> Self.Model.Action
Expand Down Expand Up @@ -387,6 +390,7 @@ extension Binding {
}

extension StoreProtocol {
@MainActor
public func binding<Value>(
get: @escaping (Self.Model) -> Value,
tag: @escaping (Value) -> Self.Model.Action
Expand Down
2 changes: 2 additions & 0 deletions Tests/ObservableStoreTests/BindingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ final class BindingTests: XCTestCase {
}

/// Test creating binding for an address
@MainActor
func testBinding() throws {
let store = Store(
state: Model(),
Expand Down Expand Up @@ -70,6 +71,7 @@ final class BindingTests: XCTestCase {
}

/// Test creating binding for an address
@MainActor
func testBindingMethod() throws {
let store = Store(
state: Model(),
Expand Down
4 changes: 4 additions & 0 deletions Tests/ObservableStoreTests/ComponentMappingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class ComponentMappingTests: XCTestCase {
}
}

@MainActor
func testForward() throws {
let store = Store(
state: ParentModel(),
Expand All @@ -150,6 +151,7 @@ class ComponentMappingTests: XCTestCase {
)
}

@MainActor
func testKeyedCursorUpdate() throws {
let store = Store(
state: ParentModel(
Expand Down Expand Up @@ -185,6 +187,7 @@ class ComponentMappingTests: XCTestCase {
)
}

@MainActor
func testCursorUpdate() throws {
let store = Store(
state: ParentModel(),
Expand All @@ -203,6 +206,7 @@ class ComponentMappingTests: XCTestCase {
)
}

@MainActor
func testKeyedCursorUpdateMissing() throws {
let store = Store(
state: ParentModel(
Expand Down
9 changes: 9 additions & 0 deletions Tests/ObservableStoreTests/ObservableStoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ final class ObservableStoreTests: XCTestCase {
self.cancellables = Set()
}

@MainActor
func testStateAdvance() throws {
let store = Store(
state: AppModel(),
Expand All @@ -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(),
Expand Down Expand Up @@ -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(),
Expand All @@ -155,6 +158,7 @@ final class ObservableStoreTests: XCTestCase {
wait(for: [expectation], timeout: 0.1)
}

@MainActor
func testAsyncFxRemovedOnComplete() {
let store = Store(
state: AppModel(),
Expand All @@ -176,6 +180,7 @@ final class ObservableStoreTests: XCTestCase {
wait(for: [expectation], timeout: 0.5)
}

@MainActor
func testPublishedPropertyFires() throws {
let store = Store(
state: AppModel(),
Expand Down Expand Up @@ -207,6 +212,7 @@ final class ObservableStoreTests: XCTestCase {
wait(for: [expectation], timeout: 0.2)
}

@MainActor
func testStateOnlySetWhenNotEqual() {
let store = Store(
state: AppModel(),
Expand Down Expand Up @@ -286,6 +292,7 @@ final class ObservableStoreTests: XCTestCase {
var subtitle: String = ""
}

@MainActor
func testUpdateMergeFx() {
let store = Store(
state: TestUpdateMergeFxState(),
Expand Down Expand Up @@ -318,6 +325,7 @@ final class ObservableStoreTests: XCTestCase {
wait(for: [expectation], timeout: 0.2)
}

@MainActor
func testCreateInit() throws {
let store = Store(
create: { environment in
Expand All @@ -343,6 +351,7 @@ final class ObservableStoreTests: XCTestCase {
wait(for: [expectation], timeout: 0.1)
}

@MainActor
func testActionsPublisher() throws {
let store = Store(
state: AppModel(),
Expand Down
1 change: 1 addition & 0 deletions Tests/ObservableStoreTests/UpdateActionsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class UpdateActionsTests: XCTestCase {
}
}

@MainActor
func testUpdateActions() throws {
let store = Store(
state: TestModel(),
Expand Down
2 changes: 2 additions & 0 deletions Tests/ObservableStoreTests/ViewStoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ final class ViewStoreTests: XCTestCase {
}

/// Test creating binding for an address
@MainActor
func testViewStore() throws {
let store = Store(
state: ParentModel(),
Expand All @@ -118,6 +119,7 @@ final class ViewStoreTests: XCTestCase {
}

/// Test creating binding for an address
@MainActor
func testViewStoreMethod() throws {
let store = Store(
state: ParentModel(),
Expand Down

0 comments on commit 00ecc9d

Please sign in to comment.