Reputation:
Integrating actors
with existing code doesn't really seem to be as simple as Apple wants you to believe. Consider the following simple actor:
actor Foo {
var value: Int = 0
}
Trying to access this property from any AppKit/UIKit
(task-less) controller just can't work because every Task
is asynchronous.
class AppKitController {
func myTaskLessFunc() {
let f = Foo()
var v: Int = -1
Task { v = await f.value }
}
}
This will give you the expected error Mutation of captured var 'v' in concurrently-executing code
, also if you tried to lock this it wouldn't work. nonisolated
actor methods also don't help, since you will run into the same problem.
So how do you read actor properties synchronous in a task-less context at all?
Upvotes: 8
Views: 4096
Reputation:
I found a way to do it by using Combine
, like this:
import Combine
actor Foo {
nonisolated let valuePublisher = CurrentValueSubject<Int, Never>(0)
var value: Int = 0 {
didSet {
valuePublisher.value = value
}
}
}
By providing an non-isolated publisher, we can propagate the actor value safely to the outside, since Publisher
s are thread safe.
Callers can either access foo.valuePublisher.value
or subscribe to it from the outside, without requiring an async context.
Upvotes: 17