I started with a clean project and added 5 buttons and 5 spacers in a VStack and all is good. When I add the 6th spacer at the bottom, the code suddenly won't compile with the error: "Ambiguous reference to member 'buildBlock()'".
What is causing this error? Is this a bug related to SwiftUI? Or is it a feature? It's not the first time I notice that VStack or HStack is limited in the number of entries, is there some documentation around this?
Not exactly confidence inspiring, should I switch back to UIKit?
HStack can contain up to 10 static views, if you need more static views, you can nest HStack inside another HStack or Group to nest views inside.
vstack() function. The vstack() function is used to stack arrays in sequence vertically (row wise). This is equivalent to concatenation along the first axis after 1-D arrays of shape (N,) have been reshaped to (1,N). This function makes most sense for arrays with up to 3 dimensions.
The VStack allows you to stack views vertically, from top to bottom. You can further customize the view by adding alignment or spacing to the VStack. VStack(alignment: .
HStack positions views in a horizontal line, VStack positions them in a vertical line, and ZStack overlays views on top of one another.
SwiftUI uses ViewBuilder
to construct the views that make up many SwiftUI views, like VStack
, HStack
, List
, etc. If you take a look at the ViewBuilder documentation, you'll see that the buildBlock
function has many copies, each with a different amount of views as arguments. The function with the most amount of views only takes in 10 views which is why you are seeing the limitation that you observed. A way to work around this is by using Group
s:
VStack { Group { Text("Placeholder 0") Text("Placeholder 1") Text("Placeholder 2") Text("Placeholder 3") Text("Placeholder 4") Text("Placeholder 5") Text("Placeholder 6") Text("Placeholder 7") Text("Placeholder 8") Text("Placeholder 9") } Group { Text("Other Placeholder 10") Text("Other Placeholder 11") Text("Other Placeholder 12") Text("Other Placeholder 13") Text("Other Placeholder 14") Text("Other Placeholder 15") Text("Other Placeholder 16") Text("Other Placeholder 17") Text("Other Placeholder 18") Text("Other Placeholder 19") } }
Although if you want 20 views that are really similar to each other, it is encouraged to use something like a ForEach
to avoid making your views too bloated. The above workaround should only be used if the >10 views are truly unique. Even then, a more SwiftUI-y method would be to split up these views into more smaller views:
VStack { SingleDigitPlaceholders() TeensPlaceholders() } struct SingleDigitPlaceholders: View { var body: some View { ForEach(0..<10) { i in Text("Placeholder \(i)") } } } struct TeensPlaceholders: View { var body: some View { ForEach(10..<20) { i in Text("Other Placeholder \(i)") } } }
Of course, in this specific example, you can just have the two ForEach
s in the original view, but in more complex cases, the point still stands. For example, in a form with many elements (e.g. in a job application form: first name, last name, address, phone number text fields, education dropdown menus, date fields, etc.) you can still split up one view into smaller components (in the job application example - a personal information view, an educational information view, etc.).
You can have at most 10 children in your VStack
(and ZStack
, HStack
, and so forth). This is strictly related to their implementation and to the implementation of the @ViewBuilder
closures in general. Look at the interfaces here below (you can find them through xCode, I slightly simplified them in order to be more readable):
public struct ViewBuilder {
/// Builds an empty view from an block containing no statements, `{ }`.
public static func buildBlock() -> EmptyView
/// Passes a single view written as a child view (e..g, `{ Text("Hello") }`) through
/// unmodified.
public static func buildBlock<Content>(_ content: Content) -> Content where Content : View
}
extension ViewBuilder {
public static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View, C1 : View
}
extension ViewBuilder {
public static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2) -> TupleView<(C0, C1, C2)> where C0 : View, C1 : View, C2 : View
}
extension ViewBuilder {
public static func buildBlock<C0, C1, C2, C3>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3) -> TupleView<(C0, C1, C2, C3)> where C0 : View, C1 : View, C2 : View, C3 : View
}
extension ViewBuilder {
public static func buildBlock<C0, C1, C2, C3, C4>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4) -> TupleView<(C0, C1, C2, C3, C4)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View
}
extension ViewBuilder {
public static func buildBlock<C0, C1, C2, C3, C4, C5>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5) -> TupleView<(C0, C1, C2, C3, C4, C5)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View
}
extension ViewBuilder {
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6) -> TupleView<(C0, C1, C2, C3, C4, C5, C6)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View, C6 : View
}
extension ViewBuilder {
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View, C6 : View, C7 : View
}
extension ViewBuilder {
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View, C6 : View, C7 : View, C8 : View
}
extension ViewBuilder {
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8, C9>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8, _ c9: C9) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View, C6 : View, C7 : View, C8 : View, C9 : View
}
As you can see you can build those kind of views with at most 10 children. Each buildBlock
method takes an exact number of views as parameters. This is because @ViewBuilder
closures, at least at the moment, don't support variadic arguments.
A workaround can be:
struct ContentView: View {
var body: some View {
VStack {
Group {
//10 views here
}
Group {
//10 views here
}
}
}
}
I have 6 views after added the Group around my views, I'm still getting the Extra argument in call error.
So this is what I did to fix the error.
struct ContentView: View {
var body: some View {
VStack {
Group {
//3 views here
}
Group {
//3 views here
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With