Search code examples
swiftuiswiftui-listswiftui-foreach

SwiftUI - Need help troubleshooting trailing closure that does not accept a closure


`I am learning swiftui and have run into a problem with trailing closures. I have tried to create a very simple app to practice some basic principles of passing data between views.

I have a client model, enclosure model and then views for adding and displaying the clients into a project list. The apps content view displays a list of all clients added. Within each client, the idea would be that you could then add enclosures etc to the project.

Here is the model I've set up.

import SwiftData
import Observation
import SwiftUI

@Model
final class Client {
    var id = UUID()
    var name: String
    var location: String
    var selectedJob: Person.RawValue
    

    init(id: UUID = UUID(), name: String, location: String, selectedJob: Person.RawValue) {
        self.id = id
        self.name = name
        self.location = location
        self.selectedJob = selectedJob
    }
    
}
extension Client {
    enum Person: String, CaseIterable {
        case homeOwner = "Home Owner"
        case contractor = "Contractor"
        case designer = "Designer"
    }
}

@Model
class Enclosure: Identifiable {
    var id = UUID()
    var room: String
    var unitType: String
    
    init(id: UUID = UUID(), room: String, unitType: String) {
        self.id = id
        self.room = room
        self.unitType = unitType
    }
}

This is the detail view where I am getting the error "Trailing closure passed to parameter of type 'FormStyleConfiguration' that does not accept a closure"

import SwiftData
import SwiftUI

struct DetailView: View {
    @Environment(\.modelContext) private var modelContext
    @Environment(\.dismiss) private var dismiss
    @Query(sort: \Enclosure.room, order: .forward, animation: .default) private var enclosures: [Enclosure]
    
    @State private var showingAddEnclosure = false
    @State private var showingAddMirror = false
    
    
    @State private var name: String = ""
    @State private var location: String = ""
    
    
    @State private var selectedJob = Client.Person.homeOwner
    
    @State var client: Client
    
    var body: some View {
        NavigationStack {
            Form {
                Section("Details") {
                    TextField("Full Name", text: $client.name)
                    TextField("Location", text: $client.location)
                    
                    Picker("Job Type", selection: $selectedJob) {
                        ForEach(Client.Person.allCases, id: \.self) { selected in
                            Text(selected.rawValue).tag(selected)
                        }
                    }
                }
                
                Section("Enclosures") {
                    List {
                        ForEach(client.enclosures) { enclosure in
                            NavigationLink(destination: EnclosureDetailView()) {
                                    VStack {
                                        Text(enclosure.room)
                                        Text(enclosure.unitType)
                                    }
                            }
                            .swipeActions {
                                Button("Delete", role: .destructive) {
                                    modelContext.delete(enclosure)
                                }
                            }
                        }
                    }
                }
            }
            .navigationTitle("Project Details")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Menu {
                        Button {
                            showingAddEnclosure.toggle()
                        } label: {
                            Text("Add Enclosure")
                        }
                        Button {
                            showingAddMirror.toggle()
                        } label: {
                            Text("Add Mirror")
                        }
                    } label: {
                        Label("Add", systemImage: "ellipsis.circle")
                    }
                }
            }
            .sheet(isPresented: $showingAddEnclosure) {
                EnclosureView()
            }
            .sheet(isPresented: $showingAddMirror) {
                EnclosureView()
            }
        }
        
    }
}

I have tried commenting out different parts of the code and when I remove the ForEach in the enclosure section the error resolves. I don't understand what syntax is incorrect so any help is appreciated.

I also tried taking the code out of the form and creating a function with a viewbuilder but my limited knowledge didn't get far with that method.

Any help is appreciated and more importantly than a solution I am hoping someone can help me better understand how to problem solve an issue like this so I can do it myself.`


Solution

  • To follow up on the comments, this case is an example of a particularly unhelpful and misleading error from Xcode. I found that by commenting out different parts of the code I would get different error messages and at one point it at last reported something useful:

    Value of type 'Client' has no dynamic member 'enclosures' using key path from root type 'Client'

    So I think your main issue is that your class Client does not have a member property enclosures, which means the statement ForEach(client.enclosures) is invalid.

    When I changed it to the following, all errors disappear and it compiles (at least):

    ForEach(enclosures) { enclosure in // not client.enclosures
    

    All other code is the same as what you posted, except that I had to improvise the two missing views:

    struct EnclosureDetailView: View {
        var body: some View {
            Text("EnclosureDetailView")
        }
    }
    
    struct EnclosureView: View {
        var body: some View {
            Text("EnclosureDetailView")
        }
    }
    

    If this leads you to new errors and you need more help then I would suggest you create a new post. You will probably get a better response another time if you can provide a minimal reproducible example, with emphasis on minimal. I suspect that the reason you didn't get much help on this occasion (and the question was downvoted) was because the code you provided was not complete (the views above were missing) and it wasn't minimal. Reducing the code to a minimum is actually a good way of isolating the problem - you may find that the errors turn more meaningful and you will be able to resolve the problem yourself.