1

Here is my code. Run the MainView struct, and click on the button which should update the word first to the word hello. It does not update at all even though the logs show that the data is correctly updated. Therefore is there no way to get the view to update when a value changes inside an enum?

The only way I got it to work was a nasty hack. To try the hack just uncomment the 3 lines of commented code and try it. Is there a better way?

I looked at this similar question, but the same problem is there -> SwiftUI two-way binding to value inside ObservableObject inside enum case

struct MainView: View {
    @State var selectedEnum = AnEnum.anOption(AnObservedObject(string: "first"))
    // @State var update = false
    var body: some View {
        switch selectedEnum {
        case .anOption(var value):
            VStack {
                switch selectedEnum {
                case .anOption(let val):
                    Text(val.string)
                }
                TestView(object: Binding(get: { value }, set: { value = $0 }),
                         callbackToVerifyChange: callback)
            }
            // .id(update)
        }
    }
    
    func callback() {
        switch selectedEnum {
        case .anOption(let value):
            print("Callback function shows --> \(value.string)")
            // update.toggle()
        }
    }
}

class AnObservedObject: ObservableObject {
    @Published var string: String
    init(string: String) {
        self.string = string
    }
}

enum AnEnum {
    case anOption(AnObservedObject)
}

struct TestView: View {
    @Binding var object: AnObservedObject
    let callbackToVerifyChange: ()->Void
    var body: some View {
        Text("Tap here to change the word 'first' to 'hello'")
            .border(Color.black).padding()
            .onTapGesture {
                print("String before tapping --> \(object.string)")
                object.string = "hello"
                print("String after tapping --> \(object.string)")
                callbackToVerifyChange()
            }
    }
}
Just a coder
  • 15,480
  • 16
  • 85
  • 138
  • Not really understand what do you try to achieve here... `selectedEnum` is not changed when you change property of reference-type AnObservedObject instance, because `anOption` contains same pointer. – Asperi Jan 30 '21 at 18:01
  • The Value inside selected enum (the `string` of AnObservedObject) has changed. So I wanted the view to reflect the change? There is a Text() view on the screen that contains the value inside the enum. And although that value has changed, the TextView still contains the same old string value -> `first`. The screen is not updated at all. So i needed any help on this... – Just a coder Jan 30 '21 at 18:07
  • I can get it to work however, if i uncomment the hack shown above. As a side note, the reasoning why I have the objects inside enums is so i have have different object types and create different view based on them. The other alternative is having an array of `Any` which I do not like so much. – Just a coder Jan 30 '21 at 18:20
  • @Asperi If i am still unclear.. then let me know. I will try to get a better work around, because the hack kills all animation because the view is forced to redraw itself. – Just a coder Jan 30 '21 at 18:46
  • The simple answer is that a value type (`struct`, `enum`) that has a reference-type property isn't being mutated when a property of that reference-type property is changed, because that property - being a reference - hasn't changed - it still points to the same thing. So, `@State var selectedEnum` doesn't observe a change, and doesn't recompute the view – New Dev Jan 30 '21 at 19:24
  • @NewDev ok. I understand why it is happening. I guess I asked the question if someone has some way to make values inside an enum work this way? Or If I had to do it, whats the best way to approach this? – Just a coder Jan 30 '21 at 22:46
  • @Justacoder, not really. That's how Swift value-types work. You'd need to assign `selectedEnum` a new value, even if it's the same case, to get it to "change" – New Dev Jan 30 '21 at 23:00
  • Instead of forcing a state change by changing another state property with `update.toggle()`, you could just add a mutating function to `AnEnum`, e.g. `extension AnEnum { mutating func update() {} }` and call that. But the main issue is why is `AnObservedObject` a `class` to begin with? This wouldn't have been a problem if it was a `struct` – New Dev Jan 30 '21 at 23:03

1 Answers1

1

You need to declare your enum Equatable.

Lucas
  • 6,675
  • 3
  • 25
  • 43