swiftxcodeswiftuiios13swift5

Ambiguous reference to member 'buildBlock()' ( Maximum Subview Limit? )


I've been trying to make an app for iOS 13 using Swift UI but I keep getting this weird error: "ambiguous reference to member 'buildBlock()'".

No matter what I do the error won't go away.

I tried commenting on sections of code at a time to see which part might have been causing the issue, but the only thing that ever worked was commenting out the entire view.

I've tried cleaning my build folder and deleting derived data. I also tried restarting my computer and Xcode multiple times, but nothing has fixed it.

I'm pretty sure that this is just an Xcode bug, but there must be a way around it, I'd really appreciate it if anyone could tell me what that is.

var body: some View {
    GeometryReader { geometry in {
        VStack {
            Button (action: self.editProfilePicture) {
                    Image(ImageNames.AccountIconImageName, bundle: Bundle.main)
                        .resizable()
                        .frame(width: geometry.size.width / SizeConstants.AccountIconSizeDiviser, height: geometry.size.width / SizeConstants.AccountIconSizeDiviser)
                        .padding()
                        .background(ColorConstants.VeryLightGrayColor)
                        .clipShape(Circle())
                }
                .accentColor(.white)
                .padding(.bottom, LargePadding)
                
                ScrollView (showsVerticalIndicator: false) {
                    
                    let const: Length? = geometry.size.width - SizeConstants.FullNameTextFieldWidthReduction
                    
                    TextBox(textBinding: self.$fullName, placeHolder: Text(Strings.FullNameString), editChanged: self.fullNameChanged)/*.padding(.bottom, SmallPadding)*/.frame(width: const)
                    TextBox(textBinding: self.$username, placeHolder: Text(Strings.UsernameString), editChanged: self.usernameChanged)//.padding(.bottom)

                    Text(verbatim: Strings.ChooseIdType).font(.footnote).color(.gray)

                    TextBox(textBinding: self.$phoneNumber, placeHolder: Text(Strings.PhoneNumberString), editChanged: self.phoneNumberChanged)//.padding(.bottom, SmallPadding)
                    TextBox(textBinding: self.$emailAddress, placeHolder: Text(Strings.EmailAddressString), editChanged: self.emailAddressChanged)//.padding(.bottom)

                    Spacer(minLength: PaddingConstants.FirstSignupSpacerMinSize)

                    TextBox(textBinding: self.$password, placeHolder: Text(Strings.PasswordFieldPlaceHolder), editChanged: self.signupPasswordChanged)//.padding(.bottom, SmallPadding)
                    TextBox(textBinding: self.$confirmPassword, placeHolder: Text(Strings.ConfirmPasswordString), editChanged: self.confirmPasswordChanged)//.padding(.bottom)

                    Spacer(minLength: PaddingConstants.SecondSignupSpacerMinSize)

                    Button (action: self.signup) {
                        Text(Strings.CreateAccountString).color(.white).font(Font.system(size: SizeConstants.LoginButtonFontSize))
                    }
                    .padding(EdgeInsets(top: PaddingConstants.CreatAccountButtonVerticalPadding,
                                        leading: PaddingConstants.CreateAccountButtonSidePadding,
                                        bottom: PaddingConstants.CreatAccountButtonVerticalPadding,
                                        trailing: PaddingConstants.CreateAccountButtonSidePadding))
                    .background(LeznoBlue)
                    .clipShape(RoundedRectangle(cornerRadius: SmallCornerRadius))
                    
                    Spacer(minLength: PaddingConstants.ThirdSignupSpacerMinSize)
                    
                    Text(Strings.AgreementString)
                    
                    HStack {
                        Button (action: {}) {
                            Text(Strings.TermsString)
                        }
                        Text(Strings.AndString)
                        Button (action: {}) {
                            Text(Strings.PrivacyString)
                        }
                    }
                    
                }
        }
        .padding()
    }
}

Screenshot of the error

EDIT:

So as it turns out I forgot that you can only have a maximum of 10 views in a view builder closure, and I had more than that. Simply putting them into groups to reduce the view count solved the error.

The error that Xcode displays is just very misleading as it turns out.

Thanks to Hamish for pointing it out


Solution

  • As @Hamish originally mentioned in comments, ViewBuilders cannot exceed over 10 subviews! So you should group items in smaller pieces and try to add them group by group.

    So instead of something like this: (This is a working example based on your original code, not exactly the same)

    struct ContentView : View {
        
        @State var firstName: String = ""
        @State var lastName: String = ""
        
        @State var phoneNumber: String = ""
        @State var emailAddress: String = ""
        
        @State var password: String = ""
        @State var confirmPassword: String = ""
        
        var body: some View {
            
            ScrollView (showsVerticalIndicator: false) {
                
                TextField($firstName, placeholder: Text("First Name"))
                TextField($lastName, placeholder: Text("Last Name"))
    
                Spacer()
                
                TextField($phoneNumber, placeholder: Text("Phone Number"))
                TextField($emailAddress, placeholder: Text("Email Address"))
                
                Spacer()
                
                TextField($password, placeholder: Text("Password"))
                TextField($confirmPassword, placeholder: Text("Confirm Password"))
                
                // ...
                
            }
            .padding()
        }
        
    }
    

    Consider breaking it into meaningful smaller groups like this:

    struct NameSectionView : View {
        
        @State var firstName: String
        @State var lastName: String
        
        var body: some View {
            Group {
                TextField($firstName, placeholder: Text("First Name"))
                TextField($lastName, placeholder: Text("Last Name"))
            }
        }
        
    }
    
    struct ContactSectionView : View {
        
        @State var phoneNumber: String
        @State var emailAddress: String
        
        var body: some View {
            Group {
                TextField($phoneNumber, placeholder: Text("Phone Number"))
                TextField($emailAddress, placeholder: Text("Email Address"))
            }
        }
        
    }
    
    struct PasswordSectionView : View {
        
        @State var password: String
        @State var confirmPassword: String
        
        var body: some View {
            Group {
                TextField($password, placeholder: Text("Password"))
                TextField($confirmPassword, placeholder: Text("Confirm Password"))
            }
        }
        
    }
    

    and use them like this:

    struct ContentView : View {
        
        @State var firstName: String = ""
        @State var lastName: String = ""
        
        @State var phoneNumber: String = ""
        @State var emailAddress: String = ""
        
        @State var password: String = ""
        @State var confirmPassword: String = ""
        
        var body: some View {
            
            ScrollView (showsVerticalIndicator: false) {
                
                NameSectionView(firstName: firstName, lastName: lastName)
    
                Spacer()
                
                ContactSectionView(phoneNumber: phoneNumber, emailAddress: emailAddress)
                
                Spacer()
                
                PasswordSectionView(password: password, confirmPassword: confirmPassword)
                
                // ...
                
            }
            .padding()
        }
        
    }
    

    Also this is more reusable if you ever want to use any of this somewhere else.


    ⭕️ Using Group

    Although this quickly fixes the limit issue by tricking the compiler, it is not a good practice and MUST NOT recommended at all to blindly Group items only to go around this limit.


    Note that there should be no hardcoded limit after introducing parameter-pack in Swift 5.9