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

SwiftUI中保留@State变量修改前旧值的最佳实现方案

保留SwiftUI中@State变量旧值的几种实用方法

针对你需要保留TextField修改的@State变量旧值的需求,下面是几种直接可行的实现方式:

方法一:用独立@State变量存储旧值

适合变量数量不多的场景,初始化时把当前值同步到旧值变量,之后通过onChange监听原变量的变化,每次变化前更新旧值:

struct ContentView: View {
    @State var name: String = "初始名字"
    @State private var oldName: String = ""
    
    var body: some View {
        TextField("输入名字", text: $name)
            .onAppear {
                // 初始化时同步旧值
                oldName = name
            }
            .onChange(of: name) { previousValue in
                // 每次值变化前,先把上一次的值存为旧值
                oldName = previousValue
            }
        
        Button("恢复旧值") {
            name = oldName
        }
    }
}

方法二:用ObservableObject封装状态与旧值

如果有多个需要保留旧值的变量,用ViewModel封装会更整洁,避免View里变量混乱:

class FormViewModel: ObservableObject {
    @Published var name: String = "初始名字"
    @Published var age: String = "20"
    
    // 存储旧值的变量
    private(set) var oldName: String = ""
    private(set) var oldAge: String = ""
    
    init() {
        // 初始化旧值
        syncOldValues()
    }
    
    // 手动调用更新旧值,也可结合监听Published变量自动触发
    func syncOldValues() {
        oldName = name
        oldAge = age
    }
}

struct ContentView: View {
    @StateObject private var viewModel = FormViewModel()
    
    var body: some View {
        VStack {
            TextField("输入名字", text: $viewModel.name)
            TextField("输入年龄", text: $viewModel.age)
            
            Button("保存并更新旧值") {
                // 先使用旧值做业务操作,再同步旧值为当前新值
                print("旧名字:\(viewModel.oldName),新名字:\(viewModel.name)")
                viewModel.syncOldValues()
            }
            
            Button("恢复旧值") {
                viewModel.name = viewModel.oldName
                viewModel.age = viewModel.oldAge
            }
        }
    }
}

方法三:自定义Property Wrapper(进阶)

如果多个页面都需要保留旧值的功能,可以封装一个自定义Property Wrapper,自动管理当前值和旧值:

@propertyWrapper
struct TrackableState<Value> {
    @State private var currentValue: Value
    private(set) var oldValue: Value
    
    init(wrappedValue: Value) {
        self.currentValue = wrappedValue
        self.oldValue = wrappedValue
    }
    
    var wrappedValue: Value {
        get { currentValue }
        set {
            oldValue = currentValue
            currentValue = newValue
        }
    }
    
    var projectedValue: Binding<Value> {
        $currentValue
    }
}

struct ContentView: View {
    @TrackableState var name: String = "初始名字"
    
    var body: some View {
        TextField("输入名字", text: $name)
        
        Button("查看新旧值") {
            print("旧值:\(name.oldValue),新值:\(name.wrappedValue)")
        }
    }
}

注意事项

  • 如果需要在TextField输入过程中实时保留旧值,用onChange或者自定义Property Wrapper的方式更合适;
  • 如果只需要在确认操作(比如点击保存按钮)前保留旧值,直接在操作前手动把当前值赋值给旧值变量即可,无需实时监听。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 03:55:11