You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何删除ObservableObject中的嵌套数组元素

SwiftUI 滑动删除 ObservableObject 嵌套数组元素

我需要在SwiftUI中实现滑动删除操作,移除ObservableObject内嵌套数组中的元素。该ObservableObject包含外层数组resultslist,每个元素是newDataModelist对象,其内部有存储MockData实例的data数组。当用户滑动删除某个MockData元素时,要从ObservableObject中移除对应项。

目前使用onDelete修饰符只能获取到内层data数组的索引indexSet,但还需要获取外层resultslist的索引,才能对ObservableObject中的数据执行删除操作。相关代码如下:

数据模型代码

struct MockData: Codable, Identifiable, Hashable {
    let id: Int
    let name, boat, time: String
    let isFavourite: Bool

    enum CodingKeys: String, CodingKey {
        case id
        case name = "Name"
        case boat = "Boat"
        case time = "Time"
    }
}

数据结构示例

[
    newDataModelist(
        id: 1, 
        date: "190623", 
        data: [
            MockData(id: 1001, name: "Rich", boat: "RS Neo", time: "10102", isFavourite: false), 
            MockData(id: 1002, name: "Isla", boat: "RS Aero", time: "5903", isFavourite: false), 
            MockData(id: 1003, name: "Ben", boat: "RS Aero", time: "5843", isFavourite: false), 
            MockData(id: 1004, name: "Dar", boat: "RS Aero", time: "5783", isFavourite: false)
        ]
    ), 
    newDataModelist(
        id: 2, 
        date: "190622", 
        data: [
            MockData(id: 1005, name: "rach", boat: "RS Neo", time: "10102", isFavourite: false), 
            MockData(id: 1006, name: "sam", boat: "RS Aero", time: "5903", isFavourite: false), 
            MockData(id: 1007, name: "nigel", boat: "RS Aero", time: "5843", isFavourite: false), 
            MockData(id: 1008, name: "pete", boat: "RS Aero", time: "5783", isFavourite: false)
        ]
    )
]

当前视图代码片段

// 未完成的onDelete逻辑
.onDelete { indexSet in
    for n in indexSet {
        observeredObject.resultslist[x].data[n]
    }
}
List {
    ForEach(observeredObject.resultslist) { result in
        ForEach(result.data) { res in
            HStack {
                Text(res.name)
                Spacer()
                Text(res.boat)
                Spacer()
                Text(res.time)
            }
        }.onDelete { indexSet in
            for n in indexSet {
                // 无法获取外层索引,无法执行删除
            }
        }
    }
}

解决方法

要实现需求,核心是在外层ForEach中获取对应的resultslist索引,结合内层的indexSet定位到要删除的元素,以下是两种可行方案:

方案1:直接在视图中获取外层索引

使用带索引的ForEach重载版本,同时获取外层数组的索引和对应的newDataModelist对象,然后在内层onDelete中执行删除:

List {
    // 外层ForEach通过enumerated()获取索引和元素
    ForEach(Array(observeredObject.resultslist.enumerated()), id: \.element.id) { outerIndex, result in
        ForEach(result.data) { res in
            HStack {
                Text(res.name)
                Spacer()
                Text(res.boat)
                Spacer()
                Text(res.time)
            }
        }.onDelete { indexSet in
            // 遍历要删除的内层索引,从对应外层元素的data数组中移除
            indexSet.forEach { innerIndex in
                // 注意:如果newDataModelist是结构体,需要先复制再修改
                var updatedModel = observeredObject.resultslist[outerIndex]
                updatedModel.data.remove(at: innerIndex)
                observeredObject.resultslist[outerIndex] = updatedModel
            }
        }
    }
}

方案2:在ObservableObject中封装删除逻辑(推荐)

遵循MVVM模式,将数据操作逻辑封装在ObservableObject内部,视图只负责触发操作:

首先确保newDataModelist的data属性是可变的(将let改为var),然后在ObservableObject类中添加删除方法:

class YourObservableObject: ObservableObject {
    @Published var resultslist: [newDataModelist] = []
    
    // 封装删除逻辑:接收外层索引和内层索引集合
    func deleteMockData(at outerIndex: Int, innerIndices: IndexSet) {
        guard outerIndex < resultslist.count else { return }
        
        var updatedModel = resultslist[outerIndex]
        innerIndices.forEach { innerIndex in
            guard innerIndex < updatedModel.data.count else { return }
            updatedModel.data.remove(at: innerIndex)
        }
        resultslist[outerIndex] = updatedModel
    }
}

然后在视图中调用该方法:

List {
    ForEach(Array(observeredObject.resultslist.enumerated()), id: \.element.id) { outerIndex, result in
        ForEach(result.data) { res in
            HStack {
                Text(res.name)
                Spacer()
                Text(res.boat)
                Spacer()
                Text(res.time)
            }
        }.onDelete { indexSet in
            observeredObject.deleteMockData(at: outerIndex, innerIndices: indexSet)
        }
    }
}

关键注意事项

  • 如果newDataModelist是结构体(值类型),修改其内部的data数组时,必须先创建副本修改,再替换回resultslist中对应的元素,否则无法触发@Published的更新。
  • 如果newDataModelist是类(引用类型),则可以直接修改data数组,无需替换整个对象。

内容的提问来源于stack exchange,提问作者richmw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 16:05:36