我正在尝试从Rest API获取数据中心列表,并在Picker中显示它们,以便用户可以选择一个。当我使用静态列表进行操作时,它可以正常工作。但是,以动态方式检索数据中心似乎无法正常工作。
我正在使用Xcode 11(GM)
这是数据中心对象
struct Datacenter:Codable, Hashable, Identifiable{
let id: String
var location: String
}
这是ObservedObject(它具有datacenters属性,该属性是datacenter对象的数组)
@ObservedObject var datacenters_controller : DatacentersController
@State private var selectedDatacenter = 0
这是我的第一次尝试:
Picker(selection: $selectedDatacenter, label: Text("Datacenter")) {
ForEach(0 ..< datacenters_controller.datacenters.count) {
Text(self.datacenters_controller.datacenters[$0].location)
}
}
Swift抱怨以下错误:
ForEach<Range<Int>, Int, Text> count (4) != its initial count (0). `ForEach(_:content:)` should only be used for *constant* data. Instead conform data to `Identifiable` or use `ForEach(_:id:content:)` and provide an explicit `id`!
然后我切换到:
Picker(selection: $selectedDatacenter, label: Text("Datacenter")) {
ForEach(datacenters_controller.datacenters) { datacenter in
Text(datacenter.location)
}
}
它“可以工作”(没有错误),但是结果不是预期的,因为尽管我可以选择一个数据中心,但它不是“存储的”,也不会在选择器中显示为选中状态。
实际结果
预期结果
有什么主意吗?我在做什么错了?
答案 0 :(得分:3)
这是一个可行的例子。关键是selectedDatacenter的类型必须与Datacenter.id(在这种情况下为String)相同。
struct ContentView: View {
@ObservedObject var datacenters_controller = DatacentersController()
@State private var selectedDatacenter = ""
var body: some View {
NavigationView {
Form {
Picker(selection: $selectedDatacenter, label: Text("Datacenter")) {
ForEach(datacenters_controller.datacenters) { datacenter in
Text(datacenter.location)
}
}
// Just here for demonstration
Text("selectedDatacenter (id): \(selectedDatacenter.isEmpty ? "Nothing yet" : selectedDatacenter)")
}
}
}
}
这是支持代码
struct Datacenter:Codable, Hashable, Identifiable{
let id: String
var location: String
}
class DatacentersController: ObservableObject {
@Published var datacenters: [Datacenter] = []
init() {
datacenters = [
Datacenter(id: "ABQ", location: "Albuquerque"),
Datacenter(id: "BOS", location: "Boston"),
Datacenter(id: "COS", location: "Colorado Springs")
]
}
}
答案 1 :(得分:0)
我认为您在选择器上缺少标签:
protocol RefreshableView where Self: UIView {
func reload()
}
extension RefreshableView {
func reload() {
print("Default implementation")
}
}
class MyView: UIView {}
extension MyView: RefreshableView {
}
标签上的Apple文档:
设置视图的标签,用于从视图列表中进行选择 选项。
答案 2 :(得分:0)
在第二次尝试中,您需要使用tag
修饰符(如LuLuGaGa所述)。您还需要更改selectedDatacenter
的类型以进行匹配。例如:
struct ContentView: View {
init(_ controller: DatacentersController) {
self.datacenters_controller = controller
self._selectedDatacenter = State(initialValue: controller.datacenters[0].id)
}
var body: some View {
NavigationView {
Form {
Picker(selection: $selectedDatacenter, label: Text("Datacenter")) {
ForEach(datacenters_controller.datacenters) {
Text($0.location).tag($0)
}
}
}
}
}
@ObservedObject private var datacenters_controller: DatacentersController
@State private var selectedDatacenter: String
}