SwiftUI .onDelete 抛出致命错误:索引超出范围

Posted

技术标签:

【中文标题】SwiftUI .onDelete 抛出致命错误:索引超出范围【英文标题】:SwiftUI .onDelete throws Fatal Error: Index out of range 【发布时间】:2020-05-07 22:11:31 【问题描述】:

我有Accounts 的列表,它们每个都有一个详细信息页面,它们通过AccountDetailView 中的@Binding 连接。当前代码运行良好,更新很好。完全没有问题。但是,当我将onDelete 修饰符添加到下面的ForEach 并在应用程序中尝试swipe to delete 手势时,它崩溃并说Fatal Error: Index out of range 两次。

我进行了一些搜索并了解到ForEach 不知何故没有得到通知-或者忽略它,idk 很多细节-并查找数组的最后一个索引。最后,它找不到它并抛出错误。

List 
    Section(header: Text(String.empty), footer: Text(Strings.SectionFooters.accountListFooter.value)) 
        ForEach(self.accountsModel.accounts.indices, id:\.self)  idx in
            NavigationLink(destination: AccountDetailView(account: self.$accountsModel.accounts[idx])) 
                AccountRow(account: self.$accountsModel.accounts[idx])
            
        .onDelete  (set) in
            self.accountsModel.accounts.remove(atOffsets: set)
        
    

id: \.self 参数保持在适当位置时,它会在AppDelegate 处引发错误,当我尝试删除参数时,应用程序工作正常,但再次onDelete 它会在NavigationLink 的行中引发相同的错误多于。

这里是AccountDetailView

struct AccountDetailView: View 

    @EnvironmentObject var accountsModel: AccountsViewModel
    @Binding var account: Account
    @State var isEditing: Bool = false

    var body: some View 
        ...
    

最终Account 类符合CodableNSObjectIndentifiable 和其他一些类。我不想仅仅因为不想让问题变得复杂且难以检查而给出所有代码。如果需要,我将提供代码的任何部分。提前致谢。

【问题讨论】:

【参考方案1】:

找到了解决办法。关于这个answer 到一个相关问题,它很清楚。显然,使用.indices 填充ForEach 会使onDelete 不起作用。相反,直接通过数组的Elements 并创建代理Bindings 正在工作。

这里更清楚的是ContentViewDetailViewBinding 的扩展以避免混乱的视图。

ContentView

struct ContentView: View 

    @EnvironmentObject var store: DataStore

    var body: some View 
        NavigationView 
            List 
                ForEach(self.store.data, id: \.id /*with or without id*/)  (data) in
                    NavigationLink(destination: DetailView(data: /*created custom initializer*/ Binding(from: data))) 
                        Text(data.name)
                    
                .onDelete  (set) in
                    self.store.data.remove(atOffsets: set)
                
            .navigationBarTitle("List")
        
    

DetailView

struct DetailView: View 

    @Binding var data: MyData

    var body: some View 
        List 
            TextField("name", text: self.$data.name)
        
        .navigationBarTitle(self.data.name)
        .listStyle(GroupedListStyle())
    

Binding 分机

extension Binding where Value: MyData 
    init(from data: MyData) 
        self.init(get: 
            data as! Value
        ) 
            dataStore.data[dataStore.data.firstIndex(of: data)!] = $0
        
    

这样,onDelete 和通过直接更新详细视图中的对象来发布更改都将起作用。

【讨论】:

以上是关于SwiftUI .onDelete 抛出致命错误:索引超出范围的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:有条件的 onDelete

.ondelete 带有部分的 SwiftUI 列表

SwiftUI .onDelete 从 ForEach 获取 var

如何使用 .reversed() 处理 SwiftUI 列表数组的 .onDelete

使用 onDelete 时索引超出范围

SwiftUI List .onDelete:索引超出范围