我正在尝试使用ForEach
在 SwiftUI 中构建选择器的选项,但范围运算符似乎没有像我预期的那样工作。
这是我的代码:
struct ContentView: View {
@State private var inputString = ""
@State private var inputUnits = 0
let units = ["Fahrenheit", "Celsius", "Kelvin"]
var body: some View {
Form {
Section(header: Text("Convert:")) {
TextField("Enter input", text: $inputString)
Picker("Unit", selection: $inputUnits) {
ForEach(0 ... 2) {
Text("(self.units[$0])")
}
}
}
}
}
}
编译器的...
范围运算符存在问题。它抛出两个错误:
- 无法推断泛型参数"ID"> 在
- "ForEach"上引用初始值设定项"init(_:content:("要求"Int"符合"可识别">
奇怪的是,..<
运算符在这里工作正常,所以如果我改用这行代码,代码会编译:
ForEach(0 ..< 3) {
这对我来说似乎是一个错误,但是这些运算符之间是否存在我不知道的区别?
是的,有区别:
对于Range<Int>
(..<
(运算符,有显式扩展ForEach
指定关联类型
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) extension ForEach where Data == Range<Int>, ID == Int, Content : View {
而对于ClosedRange<Int>
(...
(则没有这样的,它被认为是更通用的集合
/// A structure that computes views on demand from an underlying collection of /// of identified data. @available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) public struct ForEach<Data, ID, Content> where Data : RandomAccessCollection, ID : Hashable {
因此需要明确提供 ID 类型,如下所示
ForEach(0...2, id: .self) {
或者您可以声明自己的扩展
extension ForEach where Data == ClosedRange<Int>, ID == Int, Content : View {
public init(_ data: ClosedRange<Int>, @ViewBuilder content: @escaping (Int) -> Content) {
self.init(data, id: .self, content: content)
}
}
然后只需使用
ForEach(0...2) {
这是因为0 ... 2
是ClosedRange<Int>
,0 ..< 3
是Range<Int>
。
如果您在此处查看ForEach
的init
功能,您会发现有以下内容:init(Range<Int>, content: (Int) -> Content)
与您的0 ..< 3
的使用相匹配
。在 swift 的许多其他地方,你可以混合使用...
和..<
因为函数要么重载,要么有一个Collection
可以使用泛型和RangeExpression
协议。在这种情况下,由于除了您的输入之外ForEach
没有支持它的Collection
,因此重载是唯一合理的选择。
这可以像这样完成:
extension ForEach where Data == ClosedRange<Int>, ID == Int, Content: View {
public init(_ data: ClosedRange<Int>, @ViewBuilder content: @escaping (Int) -> Content) {
self.init(data, id: .self, content: content)
}
}
使用范围运算符实现 ForEach 的解决方案如下:-
对于计数 3 的数组
第一个具有封闭范围的是
ForEach(0...2, id: .self){ index in
Text("(self.array[index])")
}
二是
ForEach(0..<3, id: .self){ index in
Text("(self.array[index])")
}