Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI ForEach "Unable to infer complex closure return type; add explicit type to disambiguate"

I've been stuck on this for a good couple of days now trying to figure out what the issue is.

I have built a view which lists data which I can put in and save using core data.

My data model looks like so Data Model

I can add data to the list and read it all back without any issue, but when I try and filter the fetched results, I get the error that is in the title. The error is about half way down the code.
import CoreData


struct CollectionRow: View {
    var collectionDate = Date()
    let dateFormatter = DateFormatter()
    var body: some View {
        dateFormatter.dateStyle = .short
        dateFormatter.locale = Locale(identifier: "en_GB")
            return Text(dateFormatter.string(from: collectionDate))
    }
}

struct CollectionList: View {

    var hospital = Hospital()

    @Environment(\.managedObjectContext) var managedObjectContext

    @FetchRequest(
        entity: Collection.entity(),
        sortDescriptors: [
            NSSortDescriptor(keyPath: \Collection.date, ascending: true)
        ]
    ) var collections: FetchedResults<Collection>

    @State private var collectionName = ""


    var body: some View {
        NavigationView {
            List {
                VStack {
                    ForEach(collections, id: \.self) { collection in //Unable to infer complex closure return type; add explicit type to disambiguate
                        if self.hospital.id == collection.hospital {
                            NavigationLink(destination: CollectionRow(collectionDate: Date())){
                                CollectionRow(collectionDate: Date())
                            }
                        }
                    }
                    TextField("Test", text: $collectionName)
                    Button(action: {
                        let col = Collection(context: self.managedObjectContext)
                        col.date = Date()
                        col.id = Int16(self.collections.endIndex + 1)
                        col.hospital = self.hospital.id

                        self.hospital.addToHospToCol(col)

                        do {
                            try self.managedObjectContext.save()
                        } catch {
                            print(error)
                        }

                        self.collectionName = ""
                    }) {
                        Text("New Collection")
                    }
                }
            }
            .navigationBarTitle(Text((hospital.name ?? "") + " - " + String(hospital.id)))
        }
    }
}

EDIT: The official tutorial uses an if statement inside a ForEach, so why can't I?

ForEach(landmarkData) { landmark in
                    if !self.showFavoritesOnly || landmark.isFavorite {
                        NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
                            LandmarkRow(landmark: landmark)
                        }
                    }
                }
like image 487
Shuttleu Avatar asked Oct 15 '22 11:10

Shuttleu


1 Answers

if/else in SwiftUI can only be used inside @ViewBuilder closures, hence the ForEach failing.

More about function builders here.

A simple solution would be to wrap your code like this:

struct ForEachBuilder<Content>: View where Content: View {

    private let content: Content

    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }

    var body: some View {
        content
    }

}

And your ForEach would become:

ForEach(collections, id: \.self) { collection in 
    ForEachBuilder {
        if self.hospital.id == collection.hospital {
            // Your navigation link
        }
    }
}
like image 64
Matteo Pacini Avatar answered Oct 21 '22 01:10

Matteo Pacini