我有一个应用程序
- 分别提取数组的每个元素(通过索引)
- 然后将其绑定到可以利用单个元素(查看和编辑)的结构
但是每次数组减小大小时,都会导致索引超出范围错误,这不是直接由于我的代码引起的
据我所知,这是因为:循环用更改后的数组刷新后,在某种程度上创建的视图还没有完全删除,仍然尝试访问超出范围的部分。但这就是我能弄清楚的一切
这是我的示例代码:
import SwiftUI
struct test: View {
@State var TextArray = ["A","B","C"]
var body:some View {
VStack{
ForEach(TextArray.indices, id: \.self){index in
//Text View
TextView(text: self.$TextArray[index])
.padding()
}
//Array modifying button
Button(action: {
self.TextArray = ["A","B"]
}){
Text(" Shrink array ")
.padding()
}
}
}
}
struct TextView:View {
@Binding var text:String
var body:some View {
Text(text)
}
}
#if DEBUG
struct test_Previews: PreviewProvider {
static var previews: some View {
test()
}
}
#endif
是否有更好的方法可以满足上述两个要求,而又不会引起此问题,或者有什么方法可以避免此问题?任何回应都非常感激。
答案 0 :(得分:5)
最终了解了我所遇到的那个问题。
问题是建筑性的。它是2折:
以下代码之所以有效,是因为它循环遍历了唯一的真实来源,而没有进行复制,并且总是更新唯一的真实来源。自从您最初将其作为绑定传递以来,我什至还添加了一种方法来更改子视图中的字符串,我想您想在某个时候进行更改
import SwiftUI
class DataSource: ObservableObject {
@Published var textArray = ["A","B","C"]
}
struct Test: View {
@EnvironmentObject var data : DataSource
var body:some View {
VStack{
ForEach(self.data.textArray , id: \.self) {text in
TextView(text: self.data.textArray[self.data.textArray.firstIndex(where: {text == $0})!])
.padding()
}
//Array modifying button
Button(action: {
self.data.textArray.removeLast()
}){
Text(" Shrink array ")
.padding()
}
}
}
}
struct TextView:View {
@EnvironmentObject var data : DataSource
var text:String
var body:some View {
VStack {
Text(text)
Button(action: {
let index = self.data.textArray.firstIndex(where: {self.text == $0})!
self.data.textArray[index] = "Z"
}){
Text("Change String ")
.padding()
}
}
}
}
#if DEBUG
struct test_Previews: PreviewProvider {
static var previews: some View {
Test().environmentObject(DataSource())
}
}
#endif
答案 1 :(得分:2)
@State
似乎无法解决这个问题,但是ObservableObject
有效。
除了我的最佳猜测之外,我并没有声称要知道为什么@State
会通过努力预测用户的需求来避免重绘,但是这样做并不支持。
与此同时,ObservableObject
会在每次小的更改时重绘所有内容。有效。
class FlashcardData: ObservableObject {
@Published var textArray = ["A","B","C"]
func updateData() {
textArray = ["A","B"]
}
}
struct IndexOutOfRangeView: View {
@ObservedObject var viewModel = FlashcardData()
var body:some View {
VStack{
ForEach(viewModel.textArray.indices, id: \.self){ index in
TextView(text: self.$viewModel.textArray[index])
.padding()
}
Button(action: {
self.viewModel.textArray = ["A","B"]
}){
Text(" Shrink array ")
.padding()
}
}
}
}
struct TextView:View {
@Binding var text:String
var body:some View {
Text(text)
}
}