How to pass a String array as a binding between two SwiftUI Views?

Viewed 987

I have two SwiftUI views, ContentView and SecondView. There is a String array in ContentView that I would like to share with my SecondView. The SecondView simply needs to show the contents using a VStack.

I am trying to achieve this using the @State and Binding properties as follows. Note that I need to learn how to manually iterate over each item in the String array, instead of using something like a List.

My Current Code

struct ContentView: View {
    @State var items: [String] = ["a", "b", "c"]
    var body: some View {
        SecondView<String>(elements: $items)
    }
} 

struct SecondView: View {
    var elements: Binding<[String]>
    
    var body: some View {
        VStack {
            // Compiler errors happen in the next line.
            ForEach(elements, id: \.self) { (v: String) in
                Text(v)
            }
        }
    }
}

Trying to compile the above code yields in the following errors near ForEach in SecondView.

1. Cannot convert value of type '(String) -> Text' to expected argument type '(Binding<[String]>.Element) -> Text'
2. Generic struct 'ForEach' requires that 'Binding<[String]>' conform to 'RandomAccessCollection'

I would really appreciate any one's ideas or answers on how I can achieve this. I'm extremely new to SwiftUI and I'm having trouble understanding this concept.

--UPDATE--

Thank you @Asperi for the fast response. For anyone finding this in the future, there is a place for Binding<String>, just not as the variable's type.

Binding<String> must be used when you need a custom initializer for your struct (see below).

struct SecondView: View {
    @Binding var elements: [String]

    init(_ elements: Binding<[String]>){
        self._elements = elements
    }

    // Hidden implementation details
}
1 Answers

Here is corrected code

struct ContentView: View {
    @State var items: [String] = ["a", "b", "c"]
    var body: some View {
        SecondView(elements: $items)
    }
}

struct SecondView: View {
    @Binding var elements: [String]
    
    var body: some View {
        VStack {
            ForEach(elements, id: \.self) { v in
                Text(v)
            }
        }
    }
}
Related