Swift MVVM - 使用协议来处理 viewModel 事件

Swift MVVM - use protocol to handle viewModel events

我正在尝试将 MVVM 与委托协议结合使用。当视图模型发生变化时,我想在视图控制器中触发它。

当我想在视图控制器上使用协议来处理视图模型的事件时,我无法将协议设置到视图模型的视图控制器 class。 它给了我错误:

Argument type (SecondViewController) -> () -> SecondViewController does not conform to expected type SecondViewModelEvents

我怎样才能正确地做到这一点?

这是我的视图模型的代码:

protocol SecondViewModelEvents {
    func changeBackground()
}

class SecondViewModel:NSObject {

    var events:SecondViewModelEvents?

    init(del:SecondViewModelEvents) {
        self.events = del
    }

    func loadDataFromServer() {
        self.events?.changeBackground()
    }

}

对于我的视图控制器class:

class SecondViewController: UIViewController,SecondViewModelEvents {

    let viewModel = SecondViewModel(del: self) //Argument type '(SecondViewController) -> () -> SecondViewController' does not conform to expected type 'SecondViewModelEvents'

    @IBAction func buttonPressed(_ sender: Any) {
        self.viewModel.loadDataFromServer()
    }

    func changeBackground() {
        self.view.backgroundColor = UIColor.red
    }

}

你需要使用lazy初始化为,

lazy var viewModel =  SecondViewModel(del: self)

lazy var viewModel = { [unowned self] in SecondViewModel(del: self) }()

您正在尝试初始化视图模型变量并将视图控制器作为此时未完全初始化的委托传递。

尝试查看官方 Swift 语言指南中内容丰富且非常详细的 Initialization 页面。

由于这是用于此特定目的的协议,我们可以安全地将其限制为 类(注意代码中添加的 : class

protocol SecondViewModelEvents: class {
    func changeBackground()
}

最好使用更具描述性的命名,并对委托对象使用弱引用以避免强引用循环。

class SecondViewModel {

    weak var delegate: SecondViewModelEvents?

    init(delegate: SecondViewModelEvents) {
        self.delegate = delegate
    }

    func loadDataFromServer() {
        delegate?.changeBackground()
    }

}

您可以尝试使用可选的视图模型,它将在适当的位置进行初始化,例如 awakeFromNib():

class SecondViewController: UIViewController, SecondViewModelEvents {

    var viewModel: SecondViewModel?

    override func awakeFromNib() {
        super.awakeFromNib()

        viewModel = SecondViewModel(delegate: self)
    }

    @IBAction func buttonPressed(_ sender: Any) {
        viewModel?.loadDataFromServer()
    }

    func changeBackground() {
        view.backgroundColor = UIColor.red
    }

}

或者另一种方法是在 UIViewController 必需的初始化程序中初始化非可选视图模型:


    // ...

    var viewModel: SecondViewModel

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        self.viewModel = SecondViewModel(delegate: self)
    }

    // ...