26

我从一个干净的项目开始,在 VStack 中添加了 5 个按钮和 5 个垫片,一切都很好。当我在底部添加第 6 个间隔时,代码突然无法编译并出现错误:“对成员 'buildBlock()' 的模糊引用”。

是什么导致了这个错误?这是与 SwiftUI 相关的错误吗?或者它是一个功能?这不是我第一次注意到 VStack 或 HStack 的条目数量有限,是否有一些关于此的文档?

不完全是鼓舞人心的信心,我应该切换回 UIKit 吗?

4

3 回答 3

32

SwiftUI 用于ViewBuilder构建构成许多 SwiftUI 视图的视图,例如VStackHStackList等。如果您查看ViewBuilder文档,您会发现该buildBlock函数有许多副本,每个副本都有不同数量的视图作为参数。视图数量最多的功能只接受 10 个视图,这就是为什么您会看到您观察到的限制。解决此问题的一种方法是使用Groups:

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")
    }
}

虽然如果你想要 20 个彼此非常相似的视图,建议使用类似 a 的东西,ForEach以避免让你的视图过于臃肿。仅当大于 10 个视图确实是唯一的时,才应使用上述解决方法。即便如此,更 SwiftUI-y 的方法是将这些视图拆分为更小的视图:

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)")
        }
    }
}

当然,在这个具体的例子中,你可以只ForEach在原始视图中使用两个 s,但在更复杂的情况下,这一点仍然成立。例如,在具有许多元素的表单中(例如,在工作申请表中:名字、姓氏、地址、电话号码文本字段、教育下拉菜单、日期字段等),您仍然可以将一个视图拆分为更小的组件(在工作申请示例中 - 个人信息视图、教育信息视图等)。

于 2019-10-15T15:41:41.170 回答
8

您的VStack(and ZStack, HStack, 等等) 中最多可以有 10 个孩子。这与它们的实现以及@ViewBuilder一般闭包的实现密切相关。看看下面的接口(你可以通过 xCode 找到它们,为了更具可读性,我稍微简化了它们):

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
}

如您所见,您最多可以使用 10 个孩子构建这种视图。每种buildBlock方法都将确切数量的视图作为参数。这是因为@ViewBuilder闭包,至少目前不支持可变参数。

解决方法可以是:

struct ContentView: View {
    var body: some View {
        VStack {
            Group {
                //10 views here
            }

            Group {
                //10 views here
            }
        }
    }
}
于 2019-10-15T15:28:27.497 回答
0

在我的视图周围添加组后,我有 6 个视图,我仍然在调用错误中收到 Extra 参数。

所以这就是我为修复错误所做的。

struct ContentView: View {
    var body: some View {
        VStack {
            Group {
                //3 views here
            }

            Group {
                //3 views here
            }
        }
    }
}
于 2021-03-12T22:45:47.100 回答