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

如何在SwiftUI的TextField中使用预定义值且不覆盖原始值

解决SwiftUI中修改表单参数不影响原始预定义参数的问题

问题背景

我有两个视图ParentView、ChildView,以及Parameter类。需求是让用户选择预定义参数,将其值作为表单的初始值。点击ParentView里的"Add parameter"按钮弹出参数列表,选择后值填入表单的TextField。但现在的问题是,修改ParentView里的TextField内容时,会同时改变原始预定义参数的值,请问怎么避免这种情况?是不是要复制参数用副本填充,还是有更好的办法?

原示例代码

ParentView

struct ParentView: View {
    
    @State private var showParameters: Bool = false
    @State var chosenParameter: Parameter = Parameter(id: UUID(), name: "", notes: "")
    
    var body: some View {
        VStack {
            Form {
                Button {
                    showParameters.toggle()
                } label: {
                    Text("Add parameter")
                }
                
                Section(header: Text("Parameters")) {
                    TextField("parameter", text: $chosenParameter.name)
                    TextField("notes", text: $chosenParameter.notes)
                }
            }
            .sheet(isPresented: $showParameters) {
                ChildView(chosenParameter: $chosenParameter)
            }
        }
    }
}

#Preview {
    ParentView()
}

ChildView & Parameter类

struct ChildView: View {
    
    @Binding var chosenParameter: Parameter
    @Environment(\.dismiss) var dismiss
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(Parameter.parameterList) {parameter  in
                    Button {
                        chosenParameter = parameter
                        dismiss()
                    }label: {
                        Text(parameter.name)
                    }
                }
            }
        }
    }
}

#Preview {
    ChildView(chosenParameter: .constant(Parameter.parameterList[2]))
}

class Parameter: Identifiable {
    var id: UUID
    var name: String
    var notes: String
    
    init(id: UUID, name: String, notes: String) {
        self.id = id
        self.name = name
        self.notes = notes
    }
    
    static var parameterList: [Parameter] = [
        Parameter(id: UUID(), name: "Parameter 1", notes: "Notes 1"),
        Parameter(id: UUID(), name: "Parameter 2", notes: "Notes 2"),
        Parameter(id: UUID(), name: "Parameter 3", notes: "Notes 3"),
        ]
}

问题原因

问题出在Parameter是类(引用类型),当你把parameterList里的对象赋值给chosenParameter时,传递的是对象的引用,而非新对象。所以修改chosenParameter的属性时,本质是在修改原始预定义参数的内存数据,导致原始值被改动。

解决方法

方案一:将Parameter改为结构体(推荐)

SwiftUI对值类型的支持更好,结构体赋值时会自动创建完整副本,天然隔离原始数据和表单数据。只需要把class改成struct即可,其他代码无需修改:

struct Parameter: Identifiable {
    var id: UUID
    var name: String
    var notes: String
    
    init(id: UUID, name: String, notes: String) {
        self.id = id
        self.name = name
        self.notes = notes
    }
    
    static var parameterList: [Parameter] = [
        Parameter(id: UUID(), name: "Parameter 1", notes: "Notes 1"),
        Parameter(id: UUID(), name: "Parameter 2", notes: "Notes 2"),
        Parameter(id: UUID(), name: "Parameter 3", notes: "Notes 3"),
        ]
}

这样修改表单时,只会改动chosenParameter这个副本,原始的parameterList里的参数完全不受影响。

方案二:保留类类型,实现拷贝初始化器

如果因业务需求必须使用类,给Parameter添加一个拷贝初始化方法,在选择参数时创建原始对象的副本,确保表单修改的是独立的对象:

  1. 修改Parameter类,添加拷贝初始化器:
class Parameter: Identifiable {
    var id: UUID
    var name: String
    var notes: String
    
    init(id: UUID, name: String, notes: String) {
        self.id = id
        self.name = name
        self.notes = notes
    }
    
    // 拷贝初始化器
    init(from parameter: Parameter) {
        self.id = parameter.id
        self.name = parameter.name
        self.notes = parameter.notes
    }
    
    static var parameterList: [Parameter] = [
        Parameter(id: UUID(), name: "Parameter 1", notes: "Notes 1"),
        Parameter(id: UUID(), name: "Parameter 2", notes: "Notes 2"),
        Parameter(id: UUID(), name: "Parameter 3", notes: "Notes 3"),
        ]
}
  1. 修改ChildView里的赋值逻辑,创建副本:
Button {
    chosenParameter = Parameter(from: parameter)
    dismiss()
} label: {
    Text(parameter.name)
}

这样选择参数时,chosenParameter会指向一个新的Parameter对象,修改表单内容就不会影响原始的预定义参数了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 01:22:31