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()
}
}
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
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.
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