表单中的 SwiftUI 选择器 - 索引超出范围
SwiftUI Picker in Form - Index out of Range
当我尝试在 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[[=10=]]).tag([=10=])
}
}
//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[[=13=]]).tag([=13=])
}
}
//Text(allVM[vmIndex])
}
}
}.onAppear {
self.stockViewModel.retrieveAllVM()
}
}
}
observeSingleEvent
方法看起来是 异步的 。确保在主线程上更新 @Published
属性。
替换:
self.arrKey = arrKey
与:
DispatchQueue.main.async {
self.arrKey = arrKey
}
每次创建 ViewModel 时,您在 init 中的代码都会 运行。
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
}
}
当我尝试在 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[[=10=]]).tag([=10=])
}
}
//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[[=13=]]).tag([=13=])
}
}
//Text(allVM[vmIndex])
}
}
}.onAppear {
self.stockViewModel.retrieveAllVM()
}
}
}
observeSingleEvent
方法看起来是 异步的 。确保在主线程上更新 @Published
属性。
替换:
self.arrKey = arrKey
与:
DispatchQueue.main.async {
self.arrKey = arrKey
}
每次创建 ViewModel 时,您在 init 中的代码都会 运行。
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
}
}