Skip to content

Commit a30ed9e

Browse files
committed
🐛 Fixed a data race issue using @MainActor
1 parent 44be658 commit a30ed9e

5 files changed

Lines changed: 34 additions & 10 deletions

File tree

Sources/Dripper/Drip.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@
77

88
import Foundation
99

10-
public struct Drip<State: Observable, Action>: Dripper {
10+
public struct Drip<State: ObservableState, Action>: Dripper {
11+
12+
// MARK: Nested Types
13+
14+
public typealias Dripping = @MainActor (_ state: State, _ action: Action) -> Effect<Action>?
1115

1216
// MARK: Properties
1317

14-
@usableFromInline let drip: (State, Action) -> Effect<Action>?
18+
@usableFromInline let drip: Dripping
1519

1620
// MARK: Lifecycle
1721

1822
@inlinable
19-
public init(_ drip: @escaping (_ state: State, _ action: Action) -> Effect<Action>) {
23+
public init(_ drip: @escaping Dripping) {
2024
self.init(internal: drip)
2125
}
2226

@@ -25,7 +29,7 @@ public struct Drip<State: Observable, Action>: Dripper {
2529
}
2630

2731
@usableFromInline
28-
init(internal drip: @escaping (_ state: State, _ action: Action) -> Effect<Action>?) {
32+
init(internal drip: @escaping Dripping) {
2933
self.drip = drip
3034
}
3135

Sources/Dripper/Dripper.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ public typealias DripperOf<D: Dripper> = Dripper<D.State, D.Action>
1111

1212
// MARK: - Dripper
1313

14-
public protocol Dripper<State, Action> {
15-
associatedtype State: Observable
14+
@MainActor
15+
public protocol Dripper<State, Action>: Sendable {
16+
associatedtype State: ObservableState
1617
associatedtype Action
1718
associatedtype Body
1819

Sources/Dripper/DripperBuilder.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import Foundation
99

1010
@resultBuilder
11-
public enum DripperBuilder<State: Observable, Action> {
11+
public enum DripperBuilder<State: ObservableState, Action> {
1212
@inlinable
1313
public static func buildBlock<D: Dripper<State, Action>>(_ dripper: D) -> D {
1414
dripper
@@ -20,9 +20,20 @@ public enum DripperBuilder<State: Observable, Action> {
2020
}
2121

2222
@inlinable
23+
@MainActor
2324
public static func buildExpression(
2425
_ expression: any Dripper<State, Action>
2526
) -> Drip<State, Action> {
2627
Drip(expression)
2728
}
29+
30+
@inlinable
31+
public static func buildFinalResult<D: Dripper<State, Action>>(_ dripper: D) -> D {
32+
dripper
33+
}
34+
35+
@inlinable
36+
public static func buildOptional<D: Dripper<State, Action>>(_ wrapped: D?) -> D? {
37+
wrapped
38+
}
2839
}

Sources/Dripper/Effect.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public struct Pour<Action>: Sendable {
3333
}
3434

3535
public func callAsFunction(_ action: Action) {
36+
guard !Task.isCancelled else { return }
3637
pour(action)
3738
}
3839
}

Sources/Dripper/Station.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,25 @@ import SwiftUI
1010

1111
public typealias StationOf<D: Dripper> = Station<D.State, D.Action>
1212

13+
public typealias ObservableState = Observable & Sendable
14+
1315
// MARK: - Station
1416

1517
@dynamicMemberLookup
1618
@MainActor
17-
public final class Station<State: Observable, Action> {
19+
public final class Station<State: ObservableState, Action> {
1820

1921
// MARK: Properties
2022

21-
var state: State
22-
23+
private var state: State
2324
private let dripper: any Dripper<State, Action>
2425

26+
// MARK: Computed Properties
27+
28+
public var currentState: State {
29+
state
30+
}
31+
2532
// MARK: Lifecycle
2633

2734
public convenience init(

0 commit comments

Comments
 (0)