假设有一个像下面这样的演员
actor MyActor<State> {
private var state: State
private init(initialState: State) {
self.state = initialState
}
public func message(param: Int) {
// mutates state
...
}
}
现在我想以某种方式观察隔离属性
state
,以便它可以在 SwiftUI 中使用,它提供视图的状态 - 或其他地方。
目前,观察框架中的
@Observable
宏是没有问题的,因为它目前不支持参与者。
另一个想法是让参与者成为联合发布者,发布
state
独立属性:
所以,我会改变它:
actor MyActor<State> {
private var _state: CurrentValueSubject<State, Never>
private init(initialState: State) {
self._state = .init(initialState)
}
public func message(param: Int) {
// mutates _state
...
}
}
并且为了成为出版商:
extension MyActor: Publisher {
public typealias Output = State
public typealias Failure = Never
public func receive<S>(
subscriber: S
) where S : Subscriber, Never == S.Failure, State == S.Input {
_state.receive(subscriber: subscriber)
}
}
但是,编译器在函数中抱怨(合理)这个错误
receive
:
Actor-isolated instance method 'receive(subscriber:)' cannot be used
to satisfy nonisolated protocol requirement
消除此错误的一种方法是:
extension MyActor: Publisher {
public typealias Output = State
public typealias Failure = Never
nonisolated
public func receive<S>(
subscriber: S
) where S : Subscriber, Never == S.Failure, State == S.Input {
// Note: probably should declare `_state` nonisolated
assumeIsolated { this in
this._state.receive(subscriber: subscriber)
}
}
}
现在,通过一些小的努力并应用
receive(on:)
运算符在主线程上分派值传递,我可以将此参与者集成到
@Observable
类型或符合 ObservableObject
的类型中并使用此“模型”像往常一样在 SwiftUI 中。但是,它看起来很黑客,我不确定这是否是关于线程安全的正确代码。
也欢迎任何其他让演员“引人注目”的想法。
也许,结论是,“不要使用 actor,使用 @MainActor 和 Final 类”?
是的。请记住,标记为
@MainActor
的最后一堂课是演员。