5

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 of 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, nothing has fixed it.

I'm pretty sure that this is just an Xcode bug, but there must be away around it, I'd really appreciate 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 view 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

  • 2
    Could you please provide a _minimum_ verifiable example? If this can be reproduced using just an empty View, then please use that as your example, and show the _context_ in which this variable declaration occurs. – matt Jun 18 '19 at 19:04
  • Also, if by `vody` you mean `body`, then please say so. Show only _real_ code. – matt Jun 18 '19 at 19:06
  • And please format your code correctly. Your indentation is all wrong here. – matt Jun 18 '19 at 19:08
  • 6
    One issue I can see is that you're exceeding ViewBuilder's 10 subview limit – try using `Group { /*10 subviews here*/ } Group { /*up to 10 more views*/ }` as shown midway through https://stackoverflow.com/a/56435128/2976878. – Hamish Jun 18 '19 at 19:09
  • Wow using groups actually fixed it, they really need to work on the error messages produced by Xcode for ViewBuilder related things – Ex0ticButters Jun 18 '19 at 19:26
  • 1
    Consider extracting your code into smaller pieces like `EditProfileButton`, `NameInformationView`, `CredentialsView` and so on instead of blindly group items 10 by 10. – Mojtaba Hosseini Jun 18 '19 at 22:08
  • Errors in SwiftUI are completely misleading. Most of the time, the error shows in some place, but the actual problem is somewhere else. What I do, is start commenting parts of the code until the error disappears. That way I can usually locate what is causing it. In general, I start commenting out the last code I added which is most of the time the guilty one. Group is a good saver... although sometimes it can also introduce new problems! – kontiki Jun 19 '19 at 09:01

1 Answers1

8

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.

Jeff Hillman
  • 7,500
  • 3
  • 31
  • 34
Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278