0

I am trying to use ForEach's iterator variable in a view that requires binding.

import SwiftUI

struct MyStruct: Identifiable {
    public var id = UUID()
    var name: String
    var repetitions: Int

}

struct ContentView: View {
    @State private var mystructs :[MyStruct] = [
        MyStruct(name: "John", repetitions: 3),
        MyStruct(name: "Mark", repetitions: 9)
    ]

    var body: some View {

        List {
            ForEach (mystructs) { st in
                VStack {
                    Text("\(st.name)")
                    TextField("Name", text: self.$mystructs[0].name)
                    TextField("Name", text: $st.name) // <- Got "Ambiguous reference..." error
                }
            }
        }
    }
}

The ForEach iterator works, as demonstrated by the Text view's use of st.name. And the first TextField demonstrates that binding to mystructs' element works. However, for the second TextField which is my real use case, causes the following compiler errors:

- Use of unresolved identifier $st
- Ambiguous reference to member of 'subscript'

Any thoughts?

2
  • What are you trying to do ? Commented Feb 13, 2020 at 16:14
  • Trying to make the list dynamic where I can add/delete elements of array and at the same time modify the elements. This is a simplified code snippet; in my code I have a custom View instead of TextField and requires a binding. Commented Feb 13, 2020 at 16:20

3 Answers 3

1

$st is coming as unresolved as 'st' is not a state variable and cannot be used for binding purpose.
Also $mystructs is working because it is a declared as a State variable and can be used for binding.

Hope this is of some use for you!Thanks!

Sign up to request clarification or add additional context in comments.

Comments

1

In the described scenario it can be done the following

ForEach (mystructs.indices) { i in
    VStack {
        Text("\(self.mystructs[i].name)")
        TextField("Name", text: self.$mystructs[i].name)
    }
}

Update: variant for more generic use-case

ForEach (Array(mystructs.enumerated()), id: \.element.id) { (i, item) in
    VStack {
        Text("\(item.name)")
        TextField("Name", text: self.$mystructs[i].name)
    }
}

2 Comments

Thanks but unfortunately in my real use case the number of elements in the array would also change. E.g. if somewhere in the view a button appends another element to the array, the view would NOT display the new element because the count would stay constant, despite no compiler error.
@Hampden123, there is variant for generic case as well, please see update.
1

Building on @Asperi's answer, this also works:

var body: some View {
    List {
        Button("Add") {
            self.mystructs.append(MyStruct(name: "Pepe", repetitions: 42))
        }
        ForEach(mystructs.indices, id: \.self) { index in
            VStack {
                Text(self.mystructs[index].name)
                TextField("Name", text: self.$mystructs[index].name)
            }
        }
    }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.