英文:
How-to: MVVM ViewModel with properties that update UI elements in willSet/didSet
问题
根据这个问题,这不是正确的做法,但我该如何处理这个问题,以便在更新属性时可以更新UI元素。
在SwiftUI中,可以轻松实现这一目标,使用@Published
:
var exchangeRate: Double = 1.0 {
willSet {
guard let doubleFormattedValue = Double.format(newValue, numberStyle: .decimal, decimalPlaces: 6) else { return }
DispatchQueue.main.async {
self.rateLabel.text = String(doubleFormattedValue) + " " + self.fromCurrencyTextField.currency.rawValue
}
}
}
英文:
Based on this question, it's not the way to go but how do I go about handling this so I can update UI elements when said property is update.
This would easily be achieved in SwiftUI using @Published
var exchangeRate: Double = 1.0 {
willSet {
guard let doubleFormattedValue = Double.format(newValue, numberStyle: .decimal, decimalPlaces: 6) else { return }
DispatchQueue.main.async {
self.rateLabel.text = String(doubleFormattedValue) + " " + self.fromCurrencyTextField.currency.rawValue
}
}
}
答案1
得分: 1
Following the suggestion of @Paulw11 and this tutorial, I was able to implement the following:
private var viewModel: CurrencyConverterViewModel = CurrencyConverterViewModel()
private var subscriptions = Set<AnyCancellable>()
private func configureBinding() {
viewModel.$exchangeRate
.sink { [weak self] exchangeRate in
guard let self = self else { return }
// UI changes go here
}
.store(in: &subscriptions)
}
英文:
Following the suggestion of @Paulw11 and this tutorial, I was able to implement the following:
private var viewModel: CurrencyConverterViewModel = CurrencyConverterViewModel()
private var subscriptions = Set<AnyCancellable>()
private func configureBinding() {
viewModel.$exchangeRate
.sink { [weak self] exchangeRate in
guard let self = self else { return }
// UI changes go here
}
.store(in: &subscriptions)
}
答案2
得分: 0
ViewModel不应该包含关于视图的任何信息,你可以使用绑定(binding)与改变处理器(change handler)以及逃逸闭包(escaping)。这个解决方案不使用Combine、RxSwift、async/await等等。
例如:
enum SampleViewModelChange {
case didValueChanged
case didError(Error)
case didEverythingYouWant
}
final class SampleViewModel {
var sampleChangeHandler: ((SampleViewModelChange) -> Void)?
var exchangeRate: Double = 1.0 {
willSet {
emitSample(.didValueChanged)
}
didSet {
emitSample(.didEverythingYouWant)
}
}
func emitSample(_ change: SampleViewModelChange) {
sampleChangeHandler?(change)
}
}
在你的视图中,你可以这样使用:
class SampleVC: UIViewController {
var viewModel: SampleViewModel
override func viewDidLoad() {
super.viewDidLoad()
bindViewModel()
}
func bindViewModel() {
viewModel.sampleChangeHandler = { [weak self] change in
guard let strongSelf = self else { return }
switch change {
case .didValueChanged:
debugPrint(didValueChanged)
self.rateLabel.text = String(doubleFormattedValue) + " " + self.fromCurrencyTextField.currency.rawValue
case .didError(let error):
debugPrint(error)
case .didEverythingYouWant:
debugPrint("EverythingYouWant,比如重新加载表格或任何你想要的操作")
}
}
}
}
对我来说,MVVM 不依赖于UIView、SwiftUI或Snappkit,你可以在任何你想要的UI中使用MVVM,这是一种通用的架构。
英文:
ViewModel shouldn't have any inforamtion about the View you can use binding with change handler and escaping, this solution is without combine or rxswift or async await etc.
such as:
enum SampleViewModelChange {
case didValueChanged
case didError(Error)
case didEverythingYouWant
}
final class SampleViewModel {
var sampleChangeHandler: ((SampleViewModelChange) -> Void)?
var exchangeRate: Double = 1.0 {
willSet {
emitSample(.didValueChanged)
}
didSet {
emitSample(.didEverythingYouWant)
}
}
func emitSample(_ change: SampleViewModelChange) {
sampleChangeHandler?(change)
}
}
in your view you can have:
class SampleVC: UIViewController {
var viewModel: SampleViewModel
override func viewDidLoad() {
super.viewDidLoad()
bindViewModel()
}
func bindViewModel() {
viewModel.sampleChangeHandler = { [weak self] change in
guard let strongSelf = self else { return }
switch change {
case .didValueChanged:
debugPrint(didValueChanged)
self.rateLabel.text = String(doubleFormattedValue) + " " + self.fromCurrencyTextField.currency.rawValue
case .didError(let error):
debugPrint(error)
case .didEverythingYouWant:
debugPrint(EverythingYouWant such as reload table or every thing you want)
}
}
}
}
To me MVVM does not depend on UIView or SwiftUI or Snappkit, you can use MVVM with every UI that you want. this is a general Architecture.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论