'SwiftUI mutate from function

I have a so called FeatureHandler which holds all the buttons and listens if a feature is clicked and does a specific action accordingly, for example change the Button UI. My problem is, when I call mutating func select(state: Bool = true) the ui is never changed. The view doesn't react to changes from the 'FeatureButton'.

class FeatureHandler {
    public var buttons : [FeatureButton] = [FeatureButton]()
    init(){
        buttons.append(FeatureButton(name: "Feature1", iconName: "icon_f1", selected: true, selectedCallback: select, clickedCallback: click))
        buttons.append(FeatureButton(name: "Feature2", iconName: "icon_f2", selected: false, selectedCallback: select, clickedCallback: click))
        buttons.append(FeatureButton(name: "Feature3", iconName: "icon_f3", selected: false, selectedCallback: select, clickedCallback: click))
        buttons.append(FeatureButton(name: "Feature4", iconName: "icon_f4", selected: false, selectedCallback: select, clickedCallback: click))
        buttons.append(FeatureButton(name: "Feature5", iconName: "icon_f5", selected: false, selectedCallback: select, clickedCallback: click))
    }
    func select(id: UUID){
        for i in 0..<buttons.count {
            if(buttons[i].id == id){
                buttons[i].select()
                print(buttons[i].name)
                //DO MORE
            } else {
                buttons[i].select(state: false)
            }
        }
    }
    func click(id: UUID){
        print(buttons.count)
        for i in 0..<buttons.count {
            if(buttons[i].id == id){
                print("clicked")
            }
        }
    }
}

The code for the button itself look like this:

struct FeatureButton : View {
    
    public let id : UUID = UUID()
    
    public var name : String
    private var iconName : String
    
    @State private var finalIconName : String = ""
    @State private var textColor : Color = .white
    
    private var selected : (UUID) -> Void
    private var clicked : (UUID) -> Void
    
    init(name: String, iconName: String, selected : Bool = false,
         selectedCallback: @escaping (UUID) -> Void, clickedCallback: @escaping (UUID) -> Void ){
        self.name = name
        self.iconName = iconName
        self.selected = selectedCallback
        self.clicked = clickedCallback
        if(selected){
            _finalIconName = State(initialValue: "\(iconName)_green")
            _textColor = State(initialValue: .white)
        }else{
            _finalIconName = State(initialValue: "\(iconName)_white")
            _textColor = State(initialValue: .gray)
        }
    }
    
    mutating func select(state: Bool = true){
        if(state){
            finalIconName = "\(iconName)_green"
            textColor = .white
        }else{
            finalIconName = "\(iconName)_white"
            textColor = .gray
        }
        _finalIconName.update()
        _textColor.update()
    }
    var body : some View {
        HStack{
            Button(action: {
                selected(id)
            }, label: {
                HStack{
                    Image(systemName: finalIconName)
                    Text(name)
                        .foregroundColor(.white)
                        .colorMultiply(textColor)
                    Spacer()
                }
            })

            Button(action: {
                clicked(id)
            }, label: {
                Image("small_arrow_green")
            })
        }
    }
    
}

The parent View looks like this:

private var featureHandler : FeatureHandler = FeatureHandler()
//......           
ScrollView(showsIndicators: false){
     ForEach(0..<featureHandler.buttons.count) {
         featureHandler.buttons[$0]
     }
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source