0
votes

I'm trying to follow along with this chat app tutorial and the syntax for the ForEach function has been updated in SwiftUI. Can you please help me make this list successfully compile using SwiftUI?

import SwiftUI

struct ChatMessage : Hashable {
    var message: String
    var avatar: String
}

struct ContentView : View {
    var messages = [
        ChatMessage(message: "Hello world", avatar: "A"),
        ChatMessage(message: "Hi", avatar: "B")
    ]

    var body: some View {
        List {
            ForEach(messages.identified(by: \.self)) {
                Text($0.avatar)
                Text($0.message)
            }
        }
    }
}

I tried changing the ForEach to the updated syntax:

var body: some View {
        List {
            ForEach(messages, id: \.self) {
                Text($0.avatar)
                Text($0.message)
            }
        }
    }

However, I'm receiving an error message: "Unable to infer complex closure return type; add explicit type to disambiguate"

2
Embed your two Text views in either an HStack or a VStack. Basically, your ForEach is like creating a table cell. In a basic view you can't just place two Text subviews without a stack of some sort - and neither can you in a ForEach. - dfd
I know that I'm pretty annoying, but as I said in my answer, there's a big error in your question: ForEach is not a function, it's a struct implementing the View protocol. This is really important to understand how SwiftUI works. - matteopuc

2 Answers

2
votes

@dfd already answered you in the comment above. The problem here is not related to the ForEach view (please, note this important thing: ForEach is not a function, is a View and it's completely different from the forEach you are used to in Swift).

The ForEach view takes the elements in the array one by one and build a single view for each of them. In your @ViewBuilder closure (the closure right after the ForEach) you are passing more than one view. You must wrap your two Text in a single view depending on your needs. For example, if you want your texts to be stacked vertically you must do:

struct ChatMessage : Hashable {
    var message: String
    var avatar: String
}

struct ContentView : View {
    var messages = [
        ChatMessage(message: "Hello world", avatar: "A"),
        ChatMessage(message: "Hi", avatar: "B")
    ]

    var body: some View {
        List {
            ForEach(messages, id: \.self) {val in
                VStack {
                    Text(val.avatar)
                    Text(val.message)
                }
            }
        }
    }
}
-1
votes
struct ContentView: View {

    @State var showFavoritesOnly = true

    var body: some View {

        NavigationView {

            List {

                ForEach(landmarkData) { landmark in

                    if !self.showFavoritesOnly || landmark.isFavorite {

                        NavigationLink(destination: UserDetail(landmark: landmark)) {

                            UsersList(landmark: landmark)

                        }

                    }

                }

            }

            .navigationBarTitle(Text("Users"))

        }

    }

}