从无任务上下文同步访问 actor 属性
Accessing actor properties synchronously from task-less context
将 actors
与现有代码集成似乎并不像 Apple 希望您相信的那么简单。考虑以下简单的演员:
actor Foo {
var value: Int = 0
}
尝试从任何 AppKit/UIKit
(无任务)控制器访问此 属性 是行不通的,因为每个 Task
都是异步的。
class AppKitController {
func myTaskLessFunc() {
let f = Foo()
var v: Int = -1
Task { v = await f.value }
}
}
这会给你预期的错误 Mutation of captured var 'v' in concurrently-executing code
,而且如果你试图锁定它也不会起作用。 nonisolated
演员方法也无济于事,因为你会 运行 遇到同样的问题。
那么,您如何在无任务上下文中同步读取 actor 属性?
我找到了一种使用 Combine
的方法,如下所示:
import Combine
actor Foo {
nonisolated let valuePublisher = CurrentValueSubject<Int, Never>(0)
var value: Int = 0 {
didSet {
valuePublisher.value = value
}
}
}
通过提供非隔离的发布者,我们可以将 actor 值安全地传播到外部,因为 Publisher
s 是线程安全的。
调用者可以访问 foo.valuePublisher.value
或从外部订阅它,而不需要异步上下文。
将 actors
与现有代码集成似乎并不像 Apple 希望您相信的那么简单。考虑以下简单的演员:
actor Foo {
var value: Int = 0
}
尝试从任何 AppKit/UIKit
(无任务)控制器访问此 属性 是行不通的,因为每个 Task
都是异步的。
class AppKitController {
func myTaskLessFunc() {
let f = Foo()
var v: Int = -1
Task { v = await f.value }
}
}
这会给你预期的错误 Mutation of captured var 'v' in concurrently-executing code
,而且如果你试图锁定它也不会起作用。 nonisolated
演员方法也无济于事,因为你会 运行 遇到同样的问题。
那么,您如何在无任务上下文中同步读取 actor 属性?
我找到了一种使用 Combine
的方法,如下所示:
import Combine
actor Foo {
nonisolated let valuePublisher = CurrentValueSubject<Int, Never>(0)
var value: Int = 0 {
didSet {
valuePublisher.value = value
}
}
}
通过提供非隔离的发布者,我们可以将 actor 值安全地传播到外部,因为 Publisher
s 是线程安全的。
调用者可以访问 foo.valuePublisher.value
或从外部订阅它,而不需要异步上下文。