Search code examples
swiftuiviewbuilder

`SwiftUI` `Form` error: Trailing closure passed to parameter of type 'FormStyleConfiguration' that does not accept a closure


I have a Form and I get this mysterious error. Everything looks fine.

Error: Trailing closure passed to parameter of type 'FormStyleConfiguration' that does not accept a closure

Code

var body: some View {
    Form {
        Section("MRN/ID:") {
            TextField("MRN/ID", text: $_model.MRN)
        }
        
        NewPatientView.CreateSection($_model.Gender)
        NewPatientView.CreateSection($_model.GestationalAge)

        Section {
            DatePicker("Date of Birth", selection: $_model.DOB, in: ...Date(), displayedComponents: .date)
        }

        NewPatientView.CreateSection($_model.FatherEthnicity)
        NewPatientView.CreateSection($_model.MotherEthnicity)
        NewPatientView.CreateSection($_model.Diagnosis)
        
        Section {
            Toggle("Diagnosis Confirmed", isOn: $_model.DiagnosisConfirmed)
        }

        NewPatientView.CreatePreNatalSection($_model.Testing)
        NewPatientView.CreatePreNatalSection($_model.Imaging)
        NewPatientView.CreatePreNatalSection($_model.Exposure)
        
        Section { Toggle("Informed Consent", isOn: $_model.InformedConsent) }
        Section("Notes:") { TextEditor(text: $_model.Notes) }

        Button("Save") {
            
            do
            {
                try _model.Save()
                dismiss()
            }
            catch let ex as Exception { ShowAlert(ex.Message) }
            catch { ShowAlert("Something went wrong!") }
            
        }.alert("Error", isPresented: $_showAlert) {
            Button("OK") { _showAlert.toggle() }
        } message: { Text(_alertText) }
    }
}

Disclaimer (Rant):

This question is just to save fellow programmers from wasting their time because of a bad design decision and a terrible implementation (in my opinion).


Solution

  • After wasting around two hours, I finally (randomly) found the solution.

    The problem is SwiftUI ViewBuilder only allows each container to have 10 views at most.

    So, instead of complaining about this limitation, the compiler (or XCode) decides to throw you this error instead.

    In order to solve the problem, you need to nest your views (e.g. in a Group) to make this constraint work.

    In my opinion, this feature (!) is terrible even with a good error message. But, I don't know, maybe there are some limitations in the ViewBuilder implementation.

    Code that works

    var body: some View {
        Form {
            Section("MRN/ID:") {
                TextField("MRN/ID", text: $_model.MRN)
            }
            
            NewPatientView.CreateSection($_model.Gender)
            NewPatientView.CreateSection($_model.GestationalAge)
    
            Section {
                DatePicker("Date of Birth", selection: $_model.DOB, in: ...Date(), displayedComponents: .date)
            }
    
            NewPatientView.CreateSection($_model.FatherEthnicity)
            NewPatientView.CreateSection($_model.MotherEthnicity)
            NewPatientView.CreateSection($_model.Diagnosis)
            
            Section {
                Toggle("Diagnosis Confirmed", isOn: $_model.DiagnosisConfirmed)
            }
    
            Group {
                NewPatientView.CreatePreNatalSection($_model.Testing)
                NewPatientView.CreatePreNatalSection($_model.Imaging)
                NewPatientView.CreatePreNatalSection($_model.Exposure)
                
                Section { Toggle("Informed Consent", isOn: $_model.InformedConsent) }
                Section("Notes:") { TextEditor(text: $_model.Notes) }
            }
    
            Button("Save") {
                
                do
                {
                    try _model.Save()
                    dismiss()
                }
                catch let ex as Exception { ShowAlert(ex.Message) }
                catch { ShowAlert("Something went wrong!") }
                
            }.alert("Error", isPresented: $_showAlert) {
                Button("OK") { _showAlert.toggle() }
            } message: { Text(_alertText) }
        }
    }