[英]run when a view redraws in SwiftUI
I have a view in SwiftUI, and I would like it to both redraw and to run a closure whenever a variable in my model changes.我在 SwiftUI 中有一个视图,我希望它在模型中的变量发生变化时重绘和运行闭包。 I am using this closure to update a state var I am storing in the view, which should be the previous value of the variable in my model before it changes
我正在使用这个闭包来更新我存储在视图中的状态变量,它应该是模型中变量在它改变之前的先前值
The following code simulates my situation:下面的代码模拟了我的情况:
let viewModel = ViewModel()
struct someView: View {
@observedObject var viewModel: ViewModel = viewModel
@State var previousSomeValue: CGFloat = 0
var body: some View {
Text("\(viewModel.model.someValue)")
}
}
class ViewModel: ObservableObject {
@Published var model = Model()
}
struct model {
var someValue: CGFloat = 0
}
With this setup, if someValue ever changes, someView redraws, however, I am unable to fire a closure.使用此设置,如果 someValue 发生更改, someView 会重绘,但是,我无法触发闭包。
//Solutions I have tried: //我尝试过的解决方案:
The main one was to attach onChangeOf(_ (T)->Void)
to my view.主要的是将
onChangeOf(_ (T)->Void)
附加到我的视图中。 With .onChangeOf( viewModel.model.someValue ) { _ in //do something }
I was able to fire a closure whenever it changed however, by the time it ran, viewModel.model.someValue had already updated to the newValue, and I wasnt able to capture the old one.使用
.onChangeOf( viewModel.model.someValue ) { _ in //do something }
我可以在闭包发生变化时触发闭包,但是,当它运行时,viewModel.model.someValue 已经更新为 newValue,并且我无法捕获旧的。 I read in the documentation that this is by design and that you must capture the thing you want to store the old value of, but I (to my knowledge) am only able to capture self, viewModel, but not viewModel.model.someValue.我在文档中读到这是设计使然,您必须捕获要存储其旧值的东西,但我(据我所知)只能捕获 self、viewModel,但不能捕获 viewModel.model.someValue。
.onChangeOf( viewModel.model.someValue ) { [self] newValue in //do something } //works but doesnt capture the var
.onChangeOf( viewModel.model.someValue ) { [viewModel] newValue in //do something } //works but doesnt capture the var
.onChangeOf( viewModel.model.someValue ) { [viewModel.model.someValue] newValue in //do something } //does not compile ( Expected 'weak', 'unowned', or no specifier in capture list )
I have also tried creating a binding in the view such as Binding { gameView.model.someValue } set: { _ in }
and having the onChange observer this instead, but even when I capture self, when the closure is called, the old and new values are identicial.我还尝试在视图中创建绑定,例如
Binding { gameView.model.someValue } set: { _ in }
并使用 onChange 观察者代替,但即使我捕获自我,当调用闭包时,旧的和新值是相同的。
This seems like a common thing to do (detecting external changes and firing a closure), how should I go about it?这似乎是一件很常见的事情(检测外部变化并触发闭包),我应该怎么做?
If I correctly understood your needs then you should do this not in view but in view model, like如果我正确理解了您的需求,那么您不应该在视图中而是在视图模型中执行此操作,例如
class ViewModel: ObservableObject {
var onModelChanged: (_ old: Model, _ new: Model) -> Void
@Published var model = Model() {
didSet {
onModelChanged(oldValue, model)
}
}
init(onModelChanged: @escaping (_ old: Model, _ new: Model) -> Void = {_, _ in}) {
self.onModelChanged = onModelChanged
}
}
so instantiating ViewModel
you can provide a callback to observe values changed in model and have old and new values, like所以实例化
ViewModel
你可以提供一个回调来观察模型中改变的值并拥有新旧值,比如
@StateObject var viewModel = ViewModel() {
print("Old value: \($0.someValue)")
print("New value: \($1.someValue)")
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.