Swiftui foreach 索引超出范围 ondelete 问题

Posted

技术标签:

【中文标题】Swiftui foreach 索引超出范围 ondelete 问题【英文标题】:Swiftui foreach index out of range ondelete issue 【发布时间】:2021-04-24 00:10:56 【问题描述】:

我遇到了这个问题,onDelete 在一个视图中工作,但在我做同样的事情时它在不同的视图中不起作用。

在第一个视图中,它创建了一个空数组。

@State var funds: [Account.Fund] = []

当用户创建基金时,它会使用 ForEach 将它们打印到列表中。

if funds.count > 0
                        ForEach(funds.indices, id: \.self)  index in
                            StandardRowView(word: funds[index].name, number: funds[index].balance)
                        
                        .onDelete(perform:  indexSet in
                            funds.remove(atOffsets: indexSet)
                        )

                    

这很好用。当我滑动并按删除时,它将删除而没有任何问题。但是,要创建基金,用户必须转到不同的视图。该“资金”变量被传递。

NavigationLink(
                        destination: AddFundView(funds: $funds, savingsBalance: $balance),
                        label: 
                            Text("Funds")
                        )

在 AddFundView 中它是一个 Binding。

@Binding var funds: [Account.Fund]

现在在 AddFundView 中,它会在用户添加它们时将它们打印到列表中。代码与之前类似,但确实有一些额外的内容,因此他们可以编辑输入的金额。

ForEach(funds.indices, id: \.self)  index in
                //StandardRowView(word: funds[index].name, number: funds[index].balance)
                
                HStack
                    Text(funds[index].name)
                    Spacer()
                    TextField("Amount", value: $funds[index].balance, formatter: NumberFormatter.currency)
                        .keyboardType(.numbersAndPunctuation)
                        .multilineTextAlignment(.trailing)
                        .onChange(of: funds[index].balance, perform:  value in
                            
                            //Resets the fund balance if it exceeds the savings balance
                            if value > savingsBalance || fundsTotal > savingsBalance
                                funds[index].balance = copy[index].balance
                            
                        )
                
            
            .onDelete(perform:  indexSet in
                funds.remove(atOffsets: indexSet)
            )

当您在 AddFundView 中使用 onDelete 时,我收到此错误。

Swift/ContiguousArrayBuffer.swift:580: Fatal error: Index out of range
2021-04-23 20:06:56.400433-0400 WMMG[12180:9619685] Swift/ContiguousArrayBuffer.swift:580:     Fatal error: Index out of range

我有点困惑,因为同样的行为也在应用程序的其他地方发生。我已经看到了一些关于此的先前问题和答案,并提到它与使用“索引”有关。但是,它在使用时有效,只是由于某种我不理解的原因并非每次都有效。谁能帮我解决这个问题?

更新: 它似乎与TextField有关。如果我评论它,它工作正常。我相信这与TextField的这一部分有关。我不确定如何获得我想要的行为。

value: $funds[index].balance

【问题讨论】:

【参考方案1】:

ForEach 将每个项目作为索引返回(来自'index in'),您可以使用该项目而不是访问数组中的该项目。您只需要将资金数组本身传递给 ForEach。

我对复制部分有点困惑,但试试这个:

ForEach(funds, id: \.self)  index in
            //StandardRowView(word: index.name, number: index.balance)
            
            HStack
                Text(index.name)
                Spacer()
                TextField("Amount", value: $index.balance, formatted: NumberFormatter.currency)
                    .keyboardType(.numbersAndPunctuation)
                    .multilineTextAlignment(.trailing)
                    .onChange(of: index.balance, perform:  value in
                        
                        //Resets the fund balance if it exceeds the savings balance
                        if value > savingsBalance || fundsTotal > savingsBalance
                            index.balance = copy[index].balance // not sure here
                        
                    )
            
        
        .onDelete(perform:  indexSet in
            funds.remove(atOffsets: indexSet)
        )

【讨论】:

感谢您的回复。是的,复制部分用于跟踪原始值,因此可以重置。我知道我可以让它工作,但我想知道为什么我在第二个视图中得到该索引超出范围错误,而不是在第一个视图中。 我能想到的唯一可能给您错误的是复制数组,因为您尝试获取余额并且 onChange 可能在删除时被调用。尝试对此发表评论。 所以我以为你有那么一秒钟,但注释掉该行并没有做任何事情。我也尝试在 onDelete 中执行 copy[index].remove ,但它仍然给了我错误。我注释掉了onChange,它仍然做到了。我在onDelete中打印了funds.count,它是删除前的正确数量,我还打印了indexSet来查看它是什么。一切看起来都很好,但它不会删除。

以上是关于Swiftui foreach 索引超出范围 ondelete 问题的主要内容,如果未能解决你的问题,请参考以下文章

删除最后一个数组元素时,SwiftUI列表ForEach索引超出范围

Swiftui foreach 索引超出范围 ondelete 问题

索引超出范围 SwiftUI

SwiftUI - 索引超出范围

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

SwiftUI - 致命错误:从数组中删除元素时索引超出范围