如何在SwiftUI中使用onDisappear修饰符识别被销毁的View并同步数据源
核心问题定位
- 删除逻辑错误:你当前在
onDisappear中调用customModel.array.remove(at: id)是按索引删除元素,但customModel.array存储的是id值的集合,id值和数组索引没有绑定关系,删除非末尾元素时必然会删错数据。
- 删除逻辑错误:你当前在
- PreferenceKey实现逻辑错误:当前的
IntPreferenceKey返回值为单个Int,reduce方法只会保留最后一个CustomView的id,其余CustomView的id无法被正常识别添加到副本数组。
- PreferenceKey实现逻辑错误:当前的
修复代码
你无需修改原始数据源所在的ContentView,只需要调整CustomView、CustomModel的实现即可,修复后可以完全满足同步要求:
struct CustomView<Content: View>: View { let id: Int let content: () -> Content @StateObject private var customModel: CustomModel = CustomModel.shared var body: some View { content() .onAppear { // 视图出现时添加对应id到副本数组 if !customModel.array.contains(id) { customModel.array.append(id) } } .onDisappear { // 视图消失时删除对应id值的元素,而非按索引删除 customModel.array.removeAll { $0 == id } print("id:", id, "is removed!") } } } class CustomModel: ObservableObject { static let shared: CustomModel = CustomModel() @Published var array: [Int] = [] { didSet { // 按原始数组顺序输出,保证和原始数据源展示一致 print(array.sorted()) } } }
实现说明
- 用
onAppear代替原来的PreferenceKey逻辑,每个视图加载时主动上报自身id,逻辑更直观可控 - 删除逻辑改为匹配id值删除,不再依赖索引,避免删错数据
- 全程不需要向CustomView传递原始数据源,也不需要任何通知机制,原始数据源无任何适配改动
- 副本数组会和原始数据源的元素完全同步,增删操作都会实时响应
内容的提问来源于stack exchange,提问作者swiftPunk
相关产品推荐
相关产品推荐

