"Thread 1: Fatal error: Index out of range" when removing from array with @Binding

"Thread 1: Fatal error: Index out of range" when removing from array with @Binding

我已经 运行 解决了 SwiftUI 中的这个问题。我希望能够在用户按下按钮时从数组中删除一个项目,但是当我尝试时出现“线程 1:致命错误:索引超出范围”错误。这似乎与 IntView 采用 @Binding 的事实有关:如果我使 num 只是一个常规变量,则代码可以正常工作而不会出现错误。不幸的是,出于我的目的,我需要能够将 Binding 传递给视图(这是一个简化的案例),所以我不确定我需要做什么才能使 Binding 不会导致错误。

这是我的代码:

import SwiftUI

struct IntView: View {
    
    @Binding var num: Int // if I make this "var num: Int", there are no bugs
    
    var body: some View {
        Text("\(num)")
    }
}

struct ArrayBugView: View {
    
    @State var array = Array(0...10)
    var body: some View {
        ForEach(array.indices, id: \.self) { num in
            IntView(num: $array[num])
            
            Button(action: {
                self.array.remove(at: num)
            }, label: {
                Text("remove")
            })
            
        }
    }
}

非常感谢任何帮助!

在您的代码中,ForEachindiciesid: \.self 是错误的。 SwiftUI 中的 ForEach 视图不像传统的 for 循环。 ForEach 的文档指出:

/// It's important that the `id` of a data element doesn't change, unless
/// SwiftUI considers the data element to have been replaced with a new data
/// element that has a new identity.

这意味着我们不能在 ForEach 中使用索引、枚举或新数组。 ForEach 必须位于可识别项的实际数组中。这样 SwiftUI 就可以跟踪移动的行视图,这称为结构标识,您可以在 Demystify SwiftUI WWDC 2021.

中了解它

因此您必须将代码更改为以下内容:

import SwiftUI

struct Item: Identifiable {
    let id = UUID()
    var num: Int
}

struct IntView: View {
    
    let num: Int
    
    var body: some View {
        Text("\(num)")
    }
}

struct ArrayView: View {
    
    @State var array: [Item] = [Item(num:0), Item(num:1), Item(num:2)]

    var body: some View {
        ForEach(array) { item in
            IntView(num: item.num)
            
            Button(action: {
                if let index = array.firstIndex(where: { [=11=].id == item.id }) {
                    array.remoteAt(index) 
                }
            }, label: {
                Text("remove")
            })
            
        }
    }
}