当我尝试在Text()中显示选择器的选定数据时,发生了一个错误,称为“索引超出范围”。
但是,当我注释显示所选数据的Text()时,它可以正常工作。下面是表单中的选择器代码。
struct VMPickerView: View {
@State var vmIndex = 0
@ObservedObject var stockViewModel = StockViewModel()
var body: some View {
let allVM = self.stockViewModel.arrKey
return VStack {
Form {
Section {
Picker(selection: $vmIndex, label: Text("Location")) {
ForEach(0..<allVM.count, id: \.self) {
Text(allVM[$0]).tag($0)
}
}
//Text(allVM[vmIndex])
}
}
}
}
}
下面是我评论“ Text(allVM [vmIndex])”时应用程序的图像
下面是我用来从Firebase检索数据并将其存储到数组中的代码。
class StockViewModel: ObservableObject {
@Published var itemList = [ItemList]()
@Published var arrKey = [String]()
init() {
retrieveAllVM()
}
func retrieveAllVM() {
var arrKey = [String]()
let ref = Database.database().reference().child("VM")
ref.observeSingleEvent(of: .value, with: { snapshot in
for items in snapshot.children {
let itemSnap = items as! DataSnapshot
let allKey = itemSnap.key
arrKey.append(allKey)
}
self.arrKey = arrKey
print(self.arrKey)
})
}
}
*更改后的代码:
class StockViewModel: ObservableObject {
@Published var itemList = [ItemList]()
@Published var arrKey = [String]()
func retrieveAllVM() {
var arrKey = [String]()
let ref = Database.database().reference().child("VM")
ref.observeSingleEvent(of: .value, with: { snapshot in
for items in snapshot.children {
let itemSnap = items as! DataSnapshot
let allKey = itemSnap.key
arrKey.append(allKey)
}
DispatchQueue.main.async {
self.arrKey = arrKey
print(self.arrKey)
}
//self.arrKey = arrKey
})
}
}
struct VMPickerView: View {
@State var vmIndex = 0
@ObservedObject var stockViewModel: StockViewModel
var body: some View {
let allVM = self.stockViewModel.arrKey
return VStack {
Form {
Section {
Picker(selection: $vmIndex, label: Text("Location")) {
ForEach(0..<allVM.count, id: \.self) {
Text(allVM[$0]).tag($0)
}
}
//Text(allVM[vmIndex])
}
}
}.onAppear {
self.stockViewModel.retrieveAllVM()
}
}
}
答案 0 :(得分:0)
observeSingleEvent
方法看起来是异步。确保在主线程上更新@Published
属性。
替换:
self.arrKey = arrKey
具有:
DispatchQueue.main.async {
self.arrKey = arrKey
}
您的init代码将在每次创建ViewModel时运行。
class StockViewModel: ObservableObject {
...
init() {
retrieveAllVM()
}
您可以将呼叫retrieveAllVM
移至.onAppear
:
struct VMPickerView: View {
@State var vmIndex = 0
@ObservedObject var stockViewModel = StockViewModel()
var body: some View {
let allVM = self.stockViewModel.arrKey
return VStack {
...
}.onAppear {
self.stockViewModel.retrieveAllVM()
}
}
}
或者,不要直接在VMPickerView
中创建ViewModel。在父视图中创建ViewModel并将其传递到VMPickerView
:
struct VMPickerView: View {
@State var vmIndex = 0
@ObservedObject var stockViewModel: StockViewModel // pass only
...
}
或者,如果您使用的是SwiftUI 2.0,则可以使用@StateObject
:
struct VMPickerView: View {
@State var vmIndex = 0
@StateObject var stockViewModel = StockViewModel()
...
}
处理索引是有风险的。如果由于任何其他原因您的代码失败,请尝试使用if
或guard
语句以确保您永远不会访问无效索引。
代替:
Form {
Section {
...
Text(allVM[vmIndex])
}
}
您可以在选择器视图中添加返回当前键视图的计算属性:
@ViewBuilder
var currentKeyText: some View {
if vmIndex < stockViewModel.arrKey.count {
Text(stockViewModel.arrKey[vmIndex])
}
}
并像这样访问它:
Form {
Section {
...
currentKeyText
}
}