Accessing an Actor's Isolated State from Within a Swiftui View

Accessing an actor's isolated state from within a SwiftUI view

You need to use MainActor on your view model (named Model) indicating that all dispatching in it be on main thread (of course assuming you will use new swift concurrency system for it).

So it would look like

@MainActor 
class Model: ObservableObject {
@Published var num: Int = 0

func updateNumber(_ newNum: Int) {
self.num = newNum
}
}

Note: I'd recommend to make all updates inside class, because someone in some place might forget to update it in right way.

Swift, actor: Actor-isolated property 'scanning' can not be mutated from a non-isolated context

How can I use an actor to store/read state information correctly so the MyObj can use it to read and set state?

You cannot mutate an actor's instance variables from outside the actor. That is the whole point of actors!

Instead, give the actor a method that sets its own instance variable. You will then be able to call that method (with await).

Actor-isolated property cannot be passed 'inout' to 'async' function call

I think the issue comes from Thing being a struct. A mutating func on a struct will assign a new value to the thing property on the Controller. In order for that to work, thing is treated as an inout parameter in the call to thing.increment().

If you make thing an actor instead of a struct then increment()won't need to be a mutating func and so thing won't be treated as an inout parameter.


A possible workaround is to make a copy of the struct first, then call the mutating func on the copy, then store it back on the property in the controller.

func mutate() async {
var thing = self.thing
await thing.increment()
self.thing = thing

print(thing.counter)
}

The reason it's an issue is the UIViewControllers are all actors now, so the properties are considered actor isolated. There is a nonisolated keyword but it cant be applied to stored properties so it doesn't seem to help here.

If the controller is changed to be an actor, the error message changes a bit to say that.

error: cannot call mutating async function 'increment()' on actor-isolated property 'thing'
await thing.increment()
^

SwiftUI Using @MainActor with EnvironmentKey

Have you tried adding the main actor attribute to your environment key properties as follows?:

View Model Class:

extension HomeView {
@MainActor
internal final class ViewModel: ObservableObject {
// More code here...
}
}

EnvironmentKey for view model:

struct HomeViewModelKey: EnvironmentKey {
@MainActor
static var defaultValue = HomeView.ViewModel()
}

extension EnvironmentValues {
@MainActor
var homeViewModel: HomeView.ViewModel {
get { self[HomeViewModelKey.self] }
set { self[HomeViewModelKey.self] = newValue }
}
}

Why is it that triggering a function from within a view updates the @State variable, but triggering that same function from another view does not?

This was solved using ObservableObjects.

How to use URLSession in MainActor

Does it also run on main thread

No. That's the whole point of saying await. At that moment, the system can switch contexts to a background thread without you knowing or caring. Moreover, at await your code pauses without blocking — meaning that while you're waiting for the download, the main thread is free to do other work, the user can interact with your app, etc. Don't worry be happy.



Related Topics



Leave a reply



Submit