SwiftUI List and ForEach

What have I done wrong? I am trying to "List" a set of string values from an array, I spent all day trying to get it to work. What have I done wrong?

import SwiftUI

struct ContentView: View {
    @State private var menuItems = ["Settings", "Readings Entry", "Food Diary"]
    @State private var targets = ["Settings()", "ReadingsEntry()", "FoodDiary()"]

    var body: some View {


        NavigationStack {
           List {
               ForEach(menuItems) { menuLine in
                   print(menuLine)
               }
        }.navigationTitle("Menu")
            
        }
    }
}

The latest set of Error messages are:

Against the ForEach Line : Cannot convert value of type '[String]' to expected argument type 'Range<Int>'

Against the print line3: Type '()' cannot conform to 'View'

Answered by AnnArborMark in 789796022

For the first error, you need to add an 'id' clause, like this:

ForEach(menuItems, id: \.self) { menuLine in

Here is an explanation of the reason for this (better than I could give):

https://www.hackingwithswift.com/books/ios-swiftui/why-does-self-work-for-foreach

For the second error, the ForEach statement needs to return a view, which print does not do. So you could include a Text within the ForEach, for example:

Text(menuLine)

Accepted Answer

For the first error, you need to add an 'id' clause, like this:

ForEach(menuItems, id: \.self) { menuLine in

Here is an explanation of the reason for this (better than I could give):

https://www.hackingwithswift.com/books/ios-swiftui/why-does-self-work-for-foreach

For the second error, the ForEach statement needs to return a view, which print does not do. So you could include a Text within the ForEach, for example:

Text(menuLine)

@AnnArborMark gave a very helpful answer, so I'll just add more info to that.

The reason you're getting the error is because menuItems is an array of Strings, which do not conform to Identifiable. This means, each one does not have a unique ID for the ForEach to rely one, so you have to explicitly pass it one. The reason you have to use self is because there is no identifier to pass, so you have to pass the entire object.

If you did, say,

struct MyItem: Identifiable {
  let id = UUID()
  let name: String

and then did

@State private var menuItems: [MyItem] = [MyItem(name: "Settings"), MyItem(name: "Readings")]

You could use the ForEach like you did above: ForEach(menuItems) since there this is an implicit ForEach(menuItems, id: \.id) - it uses the key path to the ID to uniquely identify each item.

SwiftUI List and ForEach
 
 
Q