首页 > 解决方案 > 在 Swift 中为 MVVM 模式创建一个可观察的变量

问题描述

我试图观察一个变量的变化。下面的代码有效,但是当我设置isValid观察者的初始值时被触发。然后在 my 之后再次设置callAPI()变量。isValid所以我的部分逻辑代码正在过早地被检查。

实现观察者的正确方法是什么,以便在初始加载时不会触发值的初始设置?

我做这一切都错了吗?有没有更好的办法?

视图控制器

class SomeViewController: UIViewController {
    
    private let viewModel = SignInViewModel()
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        // I want to watch this variable, but when it is initialized, it's already false and fires off the bad() func
        viewModel.isValid.bind {[weak self] isValid in
            if(isValid){
                self?.good()
            }  else {
                self?.bad()
            }
        }
        
        viewModel.callAPI()

    }
    
    private func bad(){
        print("VALID --")
    }

    private func bad(){
        print("-- NOT VALID")
    }
}

我的视图模型

public class SomeViewModel {
    
    lazy var isValid = Observer(false)
    
    func callAPI(){
        // Do something on the background and set the boolean
        isValid.value = //result
    }
}

观察者

final class Observer<T> {
    typealias Listener = (T) -> Void
  
    var listener: Listener?
    var value: T {
        didSet {
            listener?(value)
        }
    }

    init(_ value: T) {
        self.value = value
    }

    func bind(listener: Listener?) {
        self.listener = listener
        listener?(value)
    }
}

标签: iosswiftmacosmvvm

解决方案


您可以listener通过修改Observer为以下内容来避免最初的火灾:

final class Observer<T> {
    typealias Listener = (T) -> Void
  
    var listener: Listener?
    var value: T {
        didSet {
            listener?(value)
        }
    }

    init(_ value: T) {
        self.value = value
    }

    func bind(listener: Listener?) {
        self.listener = listener
    }
    
    func bindAndFire(listener: Listener?) {
        self.listener = listener
        listener?(value)
    }
}

调用bind(listener:)函数只会添加新的监听器而不立即调用它,而调用bindAndFire(listener:)也会触发监听器的初始值。

或者您可以在函数中使用Bool参数bind(listener:)来确定您是否想要为初始值触发侦听器:

func bind(fire: Bool = false, listener: Listener?) {
    self.listener = listener
    if fire {
        listener?(value)
    }
}

推荐阅读