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
相关产品推荐
相关产品推荐

