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

SwiftUI如何在视图重绘时执行闭包并获取model变量旧值

解决方案

方案1:适配iOS 17+ / macOS 14+ 直接使用onChange双参数重载

SwiftUI 从iOS17开始提供了onChange的双参数重载,可以直接在闭包中拿到旧值和新值,不需要额外捕获逻辑:

import SwiftUI

let viewModel = ViewModel()

struct SomeView: View {
    @ObservedObject var viewModel: ViewModel = viewModel
    @State var previousSomeValue: CGFloat = 0 

    var body: some View {
        Text("\(viewModel.model.someValue)")
            .onChange(of: viewModel.model.someValue) { oldValue, newValue in
                // oldValue 就是变化前的值,可直接使用
                previousSomeValue = oldValue
                // 此处执行自定义逻辑
            }
    }
}

class ViewModel: ObservableObject {
    @Published var model = Model()
}

struct Model {
    var someValue: CGFloat = 0
}

注意你之前写法里的onChangeOf是拼写错误,正确的修饰符名称为onChange(of:)。

方案2:兼容iOS 13+ 低版本系统实现

如果需要适配旧版本系统,可以通过已有的@State属性存储旧值,利用State更新的时序特性实现:

struct SomeView: View {
    @ObservedObject var viewModel: ViewModel = viewModel
    @State var previousSomeValue: CGFloat = 0 

    var body: some View {
        Text("\(viewModel.model.someValue)")
            .onChange(of: viewModel.model.someValue) { newValue in
                // 此时previousSomeValue还未更新,就是变化前的旧值
                let oldValue = previousSomeValue
                // 此处执行自定义逻辑,使用oldValue即可
                // 最后更新State保存的旧值,供下一次变化使用
                previousSomeValue = newValue
            }
            .onAppear {
                // 初始化时同步初始值,避免第一次变化时旧值错误
                previousSomeValue = viewModel.model.someValue
            }
    }
}

方案3:ViewModel层托管旧值(推荐跨页面共享场景)

如果旧值需要在多个视图中使用,可以直接在ViewModel层处理旧值存储,不需要视图层额外维护状态:

import Combine
import SwiftUI

class ViewModel: ObservableObject {
    @Published var model = Model()
    @Published var previousSomeValue: CGFloat = 0
    private var cancellables = Set<AnyCancellable>()

    init() {
        previousSomeValue = model.someValue
        // 监听model的变化,自动更新旧值
        $model
            .map(\.someValue)
            .removeDuplicates()
            .dropFirst()
            .sink { [weak self] newValue in
                guard let self = self else { return }
                self.previousSomeValue = self.model.someValue
                // 此处也可以直接执行通用的业务逻辑
            }
            .store(in: &cancellables)
    }
}

视图层直接读取ViewModel的previousSomeValue即可,不需要额外处理监听逻辑。


内容的提问来源于stack exchange,提问作者Brian.Masse

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 23:03:00