Using Bindings with (Arrays of) Enumerations

Is there a good way to obtain a binding to the associated value of an enum? For now I'm using custom Bindings like this:
Code Block swift
enum Row {
case text(_ body: String)
// ...
}
struct StuffView: View {
@State var stuff: [Row] = [.text("foo"), .text("bar")]
var body: some View {
List {
ForEach(stuff.indices) { idx in
switch stuff[idx] {
case .text(let body):
HStack {
// want: TextField("Row \(idx)", text: $body)
// or TextField("Row \(idx)", text: $stuff[idx].body)
TextField(
"Row \(idx)",
text: Binding(
get: { body },
set: { stuff[idx] = .text($0) }
)
)
Spacer()
Text(body)
}
}
}
}
}
}

However, this seems overly complicated. Also, in the above example, if there are updates to the TextFields triggered by autocorrect, they're not reflected in the accompanying Text, so I suspect that this usage of bindings is not idiomatic.
Answered by OOPer in 658158022
If you would not mind defining a read-write computed property, you can write something like this:
Code Block
extension Row {
var textBody: String {
get {
switch self {
case .text(let body):
return body
default:
return ""
}
}
mutating set {
self = .text(newValue)
}
}
}
struct StuffView: View {
@State var stuff: [Row] = [.text("foo"), .text("bar")]
var body: some View {
List {
ForEach(stuff.indices) { idx in
switch stuff[idx] {
case .text(let body):
HStack {
TextField(
"Row \(idx)",
text: $stuff[idx].textBody //<-
)
Spacer()
Text(body)
}
}
}
}
}
}


Accepted Answer
If you would not mind defining a read-write computed property, you can write something like this:
Code Block
extension Row {
var textBody: String {
get {
switch self {
case .text(let body):
return body
default:
return ""
}
}
mutating set {
self = .text(newValue)
}
}
}
struct StuffView: View {
@State var stuff: [Row] = [.text("foo"), .text("bar")]
var body: some View {
List {
ForEach(stuff.indices) { idx in
switch stuff[idx] {
case .text(let body):
HStack {
TextField(
"Row \(idx)",
text: $stuff[idx].textBody //<-
)
Spacer()
Text(body)
}
}
}
}
}
}


Thank you, @OOPer, this approach works. But I'm wondering whether there are still other solutions.

The way I understand how Swift wants you to use value types is to use enums ("sum types") for modeling specialization. The nice thing (in principle) is that access to the associated values is guarded by eg a switch, which provides type safety: you can only access the values in the correct case. By adding computed properties like you suggested to the enum (which would have to be done for all cases), this type safety is lost.
Using Bindings with (Arrays of) Enumerations
 
 
Q