如何在SwiftUI中使用带有ObservedObject的Picker进行工作?

时间:2019-09-12 18:27:39

标签: swiftui

我正在尝试从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)
   }
}

它“可以工作”(没有错误),但是结果不是预期的,因为尽管我可以选择一个数据中心,但它不是“存储的”,也不会在选择器中显示为选中状态。

实际结果

Picker without selection

预期结果

Picker with a datacenter selected

有什么主意吗?我在做什么错了?

3 个答案:

答案 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
}