New Dev
New Dev

Reputation: 49590

Binding to an associated value of an enum

Is there a standard way to bind, say, a TextField to an associated value of an enum?

So, given this:

enum Choice {
  case one(String)
  case two(String)
}

Can I use it in some way as a binding in the View:

@State var choice: Choice = .one("")

var body: some View {
   TextField("", text: $choice) // <- this clearly wouldn't work
}

Such that if choice was set to choice = .one(""), then TextField would update the associated value of one.

EDIT

To clarify, can just the associated value of each be bound, so if the choice variable is .one, then .one's associated value would change; same with .two, and so forth.

Upvotes: 11

Views: 5918

Answers (2)

Asperi
Asperi

Reputation: 257563

Here is a demo of possible solution. Tested with Xcode 11.4

struct TestBindToCase: View {
    @State var choice: Choice = .one("")

    var body: some View {
        VStack {
            ChoiceField
            Divider()
            Button("Assign") { self.choice = .one("Unknown") }
        }
    }

    var ChoiceField: some View {
        let boundCase = Binding(
            get: {
                if case let .one(value) = self.choice {
                    return value
                } else { return "" }
            },
            set: { self.choice = .one($0) })
        return TextField("", text: boundCase)   // << works
    }
}

Upvotes: 1

Leo Dabus
Leo Dabus

Reputation: 236305

You can extend your enumeration and add a text property with a getter and a setter:

extension Choice {
    var text: String {
        get {
            switch self {
            case let .one(string): return string
            case let .two(string): return string
            }
        }
        set {
            switch self {
            case .one: self = .one(newValue)
            case .two: self = .two(newValue)
            }
        }
    }
}

Then you can simply pass the text property:

TextField("", text: $choice.text) 

Upvotes: 9

Related Questions