Home > Blockchain >  SwiftUI: Actors and Views - Mutable capture of 'inout' parameter 'self' is not a
SwiftUI: Actors and Views - Mutable capture of 'inout' parameter 'self' is not a

Time:11-21

I have my data stored in an Actor. I need to display the data on a view. The only way I have found to do this is to spin up a task to load the data by using an await command on the actor. This doesn't feel right as it is very clunky; it is also giving me an error which I don't understand.

Mutable capture of 'inout' parameter 'self' is not allowed in concurrently-executing code

This is my code:

actor SimpleActor
{
    func getString() -> String
    {
        return "some value"
    }

}

struct SimpleView: View
{
    var actor: SimpleActor
    @State var value: String
    
    init()
    {
        actor = SimpleActor()
        
        Task
        {
            value = await actor.getString() // error here
        }
    }
    
    var body: some View
    {
        Text(value)
            .width(100, alignment: .leading)
    }
}

What is the best way of doing this?

CodePudding user response:

There are a lot of issues in the code. For example you cannot modify a simple property without marked as @State(Object). And you cannot initialize a property (without default value) inside a Task.

Basically declare the actor as @StateObject and adopt ObservableObject

Further get the value in the .task modifier and give value a default value

actor SimpleActor : ObservableObject
{
    func getString() -> String
    {
        return "some value"
    }

}

struct DetailView: View
{
    @StateObject var actor = SimpleActor()
    @State private var value = ""
    
    var body: some View
    {
        Group {
            Text(value)
        }.task {
            value = await actor.getString()
        }
            
    }
}

CodePudding user response:

Something close to this would be a common way of doing what you want.

actor SimpleActor: ObservableObject {
    func getString() -> String {
        return "some value"
    }
}

struct SimpleView: View {
    @StateObject var actor = SimpleActor()
    @State var value: String = ""
    
    var body: some View {
        Text(value)
            .frame(width: 100, alignment: .leading)
            .task {
                value = await actor.getString()
            }
    }
}

.task is iOS 15 , so could go back to .onAppear if you need iOS 13 .

  • Related