原始代码要素 source:中间文章
,但是,当我尝试通过严格的并发检查迁移到Swift 6时,我遇到了以下与上下文相关的警告:to-call to-call to to to to aiddtarget(_:action::)'在同步的非分离上下文中
要解决此问题,我进行了几次更改,以在代码的某些部分(标记为✅更改)中使用MainActor。这是更新的代码:
protocol UIControlPublishable: UIControl {}
extension UIControlPublishable {
func publisher(for event: UIControl.Event) -> UIControl.InteractionPublisher<Self> {
return InteractionPublisher(control: self, event: event)
}
}
extension UIControl: UIControlPublishable {
@MainActor // ✅ Changed
class InteractionSubscription<S: Subscriber, C: UIControl>: Subscription where S.Input == C {
private let subscriber: S?
private weak var control: C?
private let event: UIControl.Event
init(subscriber: S,
control: C?,
event: UIControl.Event) {
self.subscriber = subscriber
self.control = control
self.event = event
self.control?.addTarget(self, action: #selector(handleEvent), for: event)
}
@objc func handleEvent(_ sender: UIControl) {
guard let control = self.control else {
return
}
_ = self.subscriber?.receive(control)
}
nonisolated func request(_ demand: Subscribers.Demand) {}
nonisolated func cancel() {
Task { @MainActor in // ✅ Changed
self.control?.removeTarget(self, action: #selector(handleEvent), for: self.event)
self.control = nil
}
}
}
enum InteractionPublisherError: Error {
case objectFoundNil
}
struct InteractionPublisher<C: UIControl>: Publisher {
typealias Output = C
typealias Failure = InteractionPublisherError
private weak var control: C?
private let event: UIControl.Event
init(control: C, event: UIControl.Event) {
self.control = control
self.event = event
}
func receive<S>(subscriber: S) where S : Subscriber, InteractionPublisherError == S.Failure, C == S.Input {
Task { @MainActor in // ✅ Changed
// ❌ Task or actor isolated value cannot be sent; this is an error in the Swift 6 language mode
guard let control = control else {
subscriber.receive(completion: .failure(.objectFoundNil))
return
}
let subscription = InteractionSubscription(
subscriber: subscriber,
control: control,
event: event
)
subscriber.receive(subscription: subscription)
}
}
}
}
此更新后,在尝试在Mainactor上下文中访问接收函数内的订户时,我遇到了以下警告:
func receive<S>(subscriber: S) where S : Subscriber, InteractionPublisherError == S.Failure, C == S.Input {
Task { @MainActor in
// ❌ Task or actor isolated value cannot be sent; this is an error in the Swift 6 language mode
guard let control = control else {
subscriber.receive(completion: .failure(.objectFoundNil))
return
}
let subscription = InteractionSubscription(
subscriber: subscriber,
control: control,
event: event
)
subscriber.receive(subscription: subscription)
}
}
即可简化任务内部的代码以仅使用订阅者在同一问题中结果:
func receive<S>(subscriber: S) where S : Subscriber, InteractionPublisherError == S.Failure, C == S.Input {
Task { @MainActor in
let temp = subscriber
}
}
我试图用任务捕获订户,但问题仍然存在。
我如何在不遇到此问题的情况下将此代码迁移到Swift 6?
commbine本身并没有真正迁移到Swift 6,由于它如何处理并发,我无法想象它永远不会迁移到Swift 6。组合订户可以在他们想要使用
{ @MainActor [subscriber] in }
和
subscribe(on:)
的任何队列上请求和接收值,因此闭合
receive(on:)
接受应该是sink
,但不是。预计,如果您
@Sendable
receive(on: DispatchQueue.global())
。
错误基本上说您不应该将
sink
发送给主要参与者 - 它应该留在原处,因为用户可以决定与
subscriber
.。
由于该出版商仅在主要演员上使用有意义,因此您不妨使用
subscribe(on:)
符合:
@preconcurrency