SwiftUI问题:使用@Published触发.sheet时保存修改值致崩溃
问题分析与解决方案
崩溃原因
- 值类型更新异常:
Transport是值类型,直接修改editedTransport?.name不会触发@Published的状态更新,导致视图与ViewModel状态不一致,关闭sheet时引发绑定冲突。 - Sheet生命周期冲突:在sheet的
onDismiss回调中设置editedTransport = nil,与保存操作中的数据修改存在竞态,导致视图销毁时访问无效的绑定实例。
修复后的代码
struct Transport: Identifiable { var id = UUID().uuidString var name: String } class TransportViewModel: ObservableObject { @Published var transports = [Transport(name: "Airplane"), Transport(name: "Car"), Transport(name: "Ship")] @Published var editedTransport: Transport? // 提供编辑name的绑定,确保值类型修改时触发状态更新 var editedName: Binding<String>? { guard let transport = editedTransport else { return nil } return Binding( get: { transport.name }, set: { newName in editedTransport = Transport(id: transport.id, name: newName) } ) } func saveTransport() { guard let unwrappedTransport = editedTransport else { return } if let index = transports.firstIndex(where: { $0.id == unwrappedTransport.id }) { transports[index] = unwrappedTransport } editedTransport = nil } func cancelEditing() { editedTransport = nil } } struct TransportListView: View { @StateObject var transportViewModel = TransportViewModel() var body: some View { List { ForEach(transportViewModel.transports) { transport in Text(transport.name) .onTapGesture { transportViewModel.editedTransport = transport } } } .sheet(item: $transportViewModel.editedTransport) { // 移除此处的nil赋值,交由按钮逻辑处理 } content: { _ in TransportEditSheet() } .environmentObject(transportViewModel) } } struct TransportEditSheet: View { @EnvironmentObject var transportViewModel: TransportViewModel @Environment(\.dismiss) var dismiss var body: some View { List { // 使用ViewModel提供的安全绑定 if let editedName = transportViewModel.editedName { TextField("输入名称", text: editedName) } Button("取消") { transportViewModel.cancelEditing() dismiss() } .foregroundColor(.red) Button("保存") { transportViewModel.saveTransport() dismiss() } .foregroundColor(.green) } } }
关键修改点
- 在ViewModel中新增
editedName绑定属性,修改名称时重新创建Transport实例,确保@Published能正确触发状态更新。 - 将
editedTransport的重置逻辑移到cancelEditing和saveTransport方法中,避免sheet的onDismiss与按钮操作的状态冲突。 - 移除
TransportEditSheet中不安全的Binding.map用法,直接使用ViewModel提供的绑定,保证视图状态稳定。
内容的提问来源于stack exchange,提问作者Nizami
相关产品推荐
相关产品推荐

