我猜你写了这样的东西:
struct ContentView: View {
var body: some View {
Picker(selection: $value, label: Text("Pick One")) {
Text("1000").tag(1000)
Text("2000").tag(2000)
Text("3000").tag(3000)
Text("4000").tag(4000)
Text("5000").tag(5000)
Text("6000").tag(6000)
Text("7000").tag(7000)
Text("8000").tag(8000)
Text("9000").tag(9000)
Text("10000").tag(10000)
}
}
@State var value: Int = 1000
}
然后您尝试添加 11000 行并收到此错误:
error: picker.xcplaygroundpage:5:31: error: cannot convert value of type 'Binding<Int>' to expected argument type 'Binding<_>'
Picker(selection: $value, label: Text("Pick One")) {
^~~~~~
问题是,由于 Swift 语言和 SwiftUI 实现方式的限制,一个视图中只能有 10 个子视图。@ViewBuilder
body.
这里有两种方法可以解决这个问题。
适合您的设计的一种方法是使用ForEach
:
struct ContentView: View {
var body: some View {
Picker(selection: $value, label: Text("Pick One")) {
ForEach(Array(stride(from: 1000, through: 20000, by: 1000))) { number in
Text("\(number)").tag(number)
}
}
}
@State var value: Int = 1000
}
如果您的项目不遵循简单的模式,另一种方法会更合适,那就是使用Group
:
struct ContentView: View {
var body: some View {
Picker(selection: $value, label: Text("Pick One")) {
Group {
Text("1000").tag(1000)
Text("2000").tag(2000)
Text("3000").tag(3000)
Text("4000").tag(4000)
Text("5000").tag(5000)
Text("6000").tag(6000)
Text("7000").tag(7000)
Text("8000").tag(8000)
Text("9000").tag(9000)
Text("10000").tag(10000)
}
Group {
Text("11000").tag(11000)
Text("12000").tag(12000)
Text("13000").tag(13000)
Text("14000").tag(14000)
Text("15000").tag(15000)
Text("16000").tag(16000)
Text("17000").tag(17000)
Text("18000").tag(18000)
Text("19000").tag(19000)
Text("20000").tag(20000)
}
}
}
@State var value: Int = 1000
}
SwiftUI 扁平化Group
子视图进入Group
的父级(在本例中,进入Picker
). Each Group
最多可以有 10 个子视图,它们本身可以是Group
s,因此通过嵌套Group
你可以在你的程序中包含任意多个显式元素Picker
。但我建议使用ForEach
.
如果您想了解 10 个子视图限制的来源,请编辑我的第二个示例,存储Picker
在这样的变量中:
struct ContentView: View {
var body: some View {
let picker = Picker(selection: $value, label: Text("Pick One")) {
Group {
...
}
}
return picker
}
}
现在按住 Option 键并单击picker
Xcode 中的变量以查看其推断类型:
让我们重新格式化它,使其更具可读性:
let picker: Picker<
Text,
Int,
TupleView<(
Group<TupleView<(
some View,
some View,
some View,
some View,
some View,
some View,
some View,
some View,
some View,
some View)>>,
Group<TupleView<(
some View,
some View,
some View,
some View,
some View,
some View,
some View,
some View,
some View,
some View)>>)>>
哇,好大的类型啊! SwiftUI 大量使用这样的泛型类型,因为它在运行时效率更高。因为这些都是struct
类型符合View
, Swift 存储了整个Picker
及其所有子项都位于一个连续的内存块中。该块可以从堆栈开始,仅当 SwiftUI 最终需要对其进行类型擦除或长期存储时,才需要将其复制到堆中。与 UIKit 相比,每个视图在创建时总是在堆上单独分配。
ViewBuilder https://developer.apple.com/documentation/swiftui/viewbuilder是组装这些复杂视图的 SwiftUI 实用程序。斯威夫特改变了每个人的身体Group
拨打电话ViewBuilder.buildBlock
,每个视图内Group
body 作为一个单独的参数ViewBuilder.buildBlock
。每个参数都可以是一个单独的类型(例如Group
可以有一些Text
儿童和一些Image
孩子们)。但 Swift 不支持可变泛型,所以ViewBuilder
必须定义一个版本buildBlock
采用单个视图的版本,采用两个视图的版本,以及采用三个视图的版本,依此类推。它不能定义无限数量的方法,因为那样的话 SwiftUI 框架就会无限大。所以它停在 10 个参数处:
static func buildBlock() -> EmptyView
Builds an empty view from a block containing no statements.
static func buildBlock<Content>(Content) -> Content
Passes a single view written as a child view through unmodified.
static func buildBlock<C0, C1>(C0, C1) -> TupleView<(C0, C1)>
static func buildBlock<C0, C1, C2>(C0, C1, C2) -> TupleView<(C0, C1, C2)>
static func buildBlock<C0, C1, C2, C3>(C0, C1, C2, C3) -> TupleView<(C0, C1, C2, C3)>
static func buildBlock<C0, C1, C2, C3, C4>(C0, C1, C2, C3, C4) -> TupleView<(C0, C1, C2, C3, C4)>
static func buildBlock<C0, C1, C2, C3, C4, C5>(C0, C1, C2, C3, C4, C5) -> TupleView<(C0, C1, C2, C3, C4, C5)>
static func buildBlock<C0, C1, C2, C3, C4, C5, C6>(C0, C1, C2, C3, C4, C5, C6) -> TupleView<(C0, C1, C2, C3, C4, C5, C6)>
static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7>(C0, C1, C2, C3, C4, C5, C6, C7) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7)>
static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8>(C0, C1, C2, C3, C4, C5, C6, C7, C8) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8)>
static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8, C9>(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)>
这就是为什么任何其内容定义的视图ViewBuilder
(包括VStack
, HStack
, ZStack
, Picker
, List
, Group
等)只能有 10 个直接子视图。