我在我的 ContentView 组件中构建了一个水平滚动的 ForEach UI,它显示了一组自定义对象(结构形式)。当我尝试删除项目时,我收到“致命错误:索引超出范围”错误。
问题是当我删除一个项目时,实际的数组本身会更新,但特定的 AssetView(下面的组件)组件没有更新,因此它最终会迭代到不再存在的索引。知道可能是什么问题吗?下面是我的代码:
List<WebElement> NameColumns = table.findElements(By.xpath("//tr/td[" + col_name_position + "]"));
for (WebElement e : NameColumns) {
String[] strArray = new String[3];
strArray[?] = (e.getText());
System.out.println(e.getText());
}
struct ContentView: View {
@ObservedObject var assetStore: AssetStore
var body: some View {
ScrollView (.horizontal) {
ForEach(assetStore.assets.indices, id: \.self) { index in
AssetView(
asset: $assetStore.assets[index],
assetStore: assetStore,
smallSize: geo.size.height <= 667
)
.padding(.bottom)
}
}
}
}
这是我将所有资产对象读/写到我的应用程序的 Documents 文件夹的地方。
struct AssetView: View {
@Binding var asset: Asset
@ObservedObject var assetStore: AssetStore
var smallSize: Bool
@State var editAsset: Bool = false
var body: some View {
VStack(alignment: .center, spacing: smallSize ? -10 : 0) {
HStack {
TagText(tagName: asset.name)
.onTapGesture {
editAsset.toggle()
}
Spacer()
DisplayCurrentValues(
forCurrentValueText: asset.getCurrentValueString,
forCurrentValueLabel: "Current Value"
)
.onTapGesture {
editAsset.toggle()
}
}
DisplayStepper(asset: $asset, title: "YoY Growth", type: .growth)
DisplayStepper(asset: $asset, title: "Recurring Deposit", type: .recurring)
}
.sheet(isPresented: $editAsset, content: {
EditAsset(assetStore: assetStore, currentValue: String(asset.currentValue), name: asset.name, asset: $asset)
})
}
}
class AssetStore: ObservableObject {
let assetsJSONURL = URL(fileURLWithPath: "Assets",
relativeTo: FileManager.documentsDirectoryURL).appendingPathExtension("json")
@Published var assets: [Asset] = [] {
didSet {
saveJSONAssets()
}
}
init() {
print(assetsJSONURL)
loadJSONAssets()
}
private func loadJSONAssets() {
guard FileManager.default.fileExists(atPath: assetsJSONURL.path) else {
return
}
let decoder = JSONDecoder()
do {
let assetsData = try Data(contentsOf: assetsJSONURL)
assets = try decoder.decode([Asset].self, from: assetsData)
} catch let error {
print(error)
}
}
private func saveJSONAssets() {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
do {
let assetsData = try encoder.encode(assets)
try assetsData.write(to: assetsJSONURL, options: .atomicWrite)
} catch let error {
print(error)
}
}
public func deleteAsset(atIndex id: Asset) {
let index = assets.firstIndex(where: { $0.id == id.id})
assets.remove(at: index!)
}
}
答案 0 :(得分:2)
我认为这是因为您的 ForEach
依赖于索引,而不是 Asset
本身。但是,如果去掉 indices
,则必须为 Asset
编写新的绑定。这是我认为它可能的样子:
ForEach(assetStore.assets, id: \.id) { asset in
AssetView(
asset: assetStore.bindingForId(id: asset.id),
assetStore: assetStore,
smallSize: geo.size.height <= 667
)
.padding(.bottom)
}
然后在您的 AssetStore
中:
func bindingForId(id: UUID) -> Binding<Asset> {
Binding<Asset> { () -> Asset in
self.assets.first(where: { $0.id == id }) ?? Asset()
} set: { (newValue) in
self.assets = self.assets.map { asset in
if asset.id == id {
return newValue
} else {
return asset
}
}
}
}