user187676
user187676

Reputation:

Accessing actor properties synchronously from task-less context

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

Answers (1)

user187676
user187676

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 Publishers are thread safe.

Callers can either access foo.valuePublisher.value or subscribe to it from the outside, without requiring an async context.

Upvotes: 17

Related Questions