MVVM和数据绑定

作者: 豆志昂扬 | 来源:发表于2017-08-08 13:19 被阅读765次

在前面的文章iOS常见架构中介绍了MVVM, 针对其中的核心点 - 数据绑定(Data Binding)并没有具体说明,今天来聊一聊如何用Swift 语言如何实现数据绑定。

MVVM

数据绑定作为View 和 ViewModel之间的桥梁,无论绑定方向是双向还是单向,都是为了让两个数据层以完全透明的方式联通。

遗憾的事,iOS 原生开发工具集并不支持数据绑定(Android开发者就幸福多了),开发者只能使用第三方框架或自己重新来实现。我们来看看当前一些主流的思路。

�委托

如果不想学习和引进新的框架,可以使用iOS SDK常用的 委托模式。
经验丰富的iOS开发者都知道委托需要手动设置,数据绑定不仅失去了透明的特性,模式也去进于MVP。
使用代理需要ViewModel持有代理的引用,代理的实现者是View(MVVM中Controller也属于View),这样ViewModel可以更新View, 而不依赖于View。

代码样例:

class ViewController: UIViewController, ViewModelDelegate {
    @IBOutlet private weak var userLabel: UILabel?
    private let viewModel: ViewModel

    init(viewModel: ViewModel) {
        self.viewModel = viewModel
        super.init(nibName: nil, bundle: nil)
        viewModel.delegate = self
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    func userNameDidChange(text: String) {
        userLabel?.text = text
    }
}

protocol ViewModelDelegate: class {
    func userNameDidChange(text: String)
}

class ViewModel {
    init() {
        userName = "王大路"
    }
    private var userName: String {
        didSet {
            delegate?.userNameDidChange(text: userName)
        }
    }
    weak var delegate: ViewModelDelegate? {
        didSet {
            delegate?.userNameDidChange(text: userName)
        }
    }
}

闭包

闭包的策略类似于委托代理,主要是在ViewModel内定义闭包作为属性,通过闭包来更新View,在使用闭包时注意避免出现循环引用。
关于如何避免循环引用可以参看文章 Swift闭包和函数

代码样例:

class ViewController: UIViewController {
    @IBOutlet private weak var userLabel: UILabel?
    private let viewModel: ViewModel

    init(viewModel: ViewModel) {
        self.viewModel = viewModel
        super.init(nibName: nil, bundle: nil)
        viewModel.userNameDidChange = { [weak self] (text: String) in
            self?.userNameDidChange(text: text)
        }
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    func userNameDidChange(text: String) {
        userLabel?.text = text
    }
}

class ViewModel {
    var userNameDidChange: ((String) -> Void)? {
        didSet {
            userNameDidChange?(userName)
        }
    }
    private var userName: String {
        didSet {
            userNameDidChange?(userName)
        }
    }
    init() {
        userName = "李小璐"
    }
}

RxSwift (or ReactiveCocoa)

RxSwiftReactiveX 家族中的Swift版本,其和 RxJava, RxJavascript, and 框架都是类似的,掌握了一个,其余的会容易上手。

ReactiveX家族

利用这些框架可以轻松实现响应式函数编程

代码样例

class ViewController: UIViewController {
    @IBOutlet private weak var userLabel: UILabel!
    private let viewModel: ViewModel
    private let disposeBag: DisposeBag

    private func bindToViewModel() {
        viewModel.myProperty
            .drive(userLabel.rx.text)
            .disposed(by: disposeBag)
    }
}

关于如何使用RxSwift请参看官方文档,这里就不做介绍了。

如果不喜欢 RxSwift 框架,可以尝试 ReactiveCocoa。如果不习惯响应式函数编程,只能多花几小时熟悉,它和传统的编程方式区别很大。

自实现简单binding样例

源码下载

更多

获取更多内容请关注微信公众号豆志昂扬:

  • 直接添加公众号豆志昂扬
  • 微信扫描下图二维码;

相关文章

网友评论

    本文标题:MVVM和数据绑定

    本文链接:https://www.haomeiwen.com/subject/cfozlxtx.html