当前位置: 首页>后端>正文

MVVM架构设计在iOS中的实践方式

一、iOS的MVVM

下图是MVVM-C设计模式的结构图,其中的C指的不是控制器,而是作为展示或者关闭控制器的Coordinate(协调器)。在开发中,我们一般在Controller中完成展示或者关闭控制器的任务,所以这里我们不关注协调器。

MVVM架构设计在iOS中的实践方式,第1张
MVVM-C.png
1. 职责划分

相比MVC来说,新增了一个VM, 下面是各个模块的职责:
VMVMVM之间的桥梁, 提供一系列属性用于View的显示,属性包含将Model变形转换为View展示时应有的值。在iOS中通常还会负责网络请求及Model更新。
VC:负责建立VM中属性与View的绑定关系;负责交互事件响应的具体逻辑;如果不建立图中协调器时,通常还包括还包括页面的跳转逻辑。
V: 视图的具体创建和用户交互监听,模型中数据的呈现逻辑。
M:负责存储和管理应用程序所需的数据,以及执行相关的业务逻辑。它不应该与V或者VM或者控制器产生耦合。

2. 响应式编程RxSwift来做绑定
  • 上述提到VC中负责建立绑定关系,我们可以使用KVO来实现,但不推荐;RxSwift是专门用于响应式编程的一套框架,提供了很多变形相关的函数。
  • 使用RxSwift,可以根据需要来实现单向或者双向的绑定,当我们熟练RxSwift的函数后,能提升我们的代码质量和便捷性。

二、一个响应式编程例子

这里是使用RxSwift的简单介绍,如果不感兴趣可以跳过。

var modelObject: ModelObject! 
var disposeBag = DisposeBag()

override func viewDidLoad() { 
    super.viewDidLoad() 
    
    modelObject.valueObservable.map { possibleValue -> String in 
        if let value = possibleValue { 
            return "Selected value is: \(value)" 
        } else { 
            return "No value selected" 
        } 
    }.bind(to: self.textLabel.rx.text).disposed(by: disposeBag) 
}
1. 为什么绑定很重要?

如上代码,相比于在很多地方设置 textLabel.text的值,现在这个 textLabel 只会在最后被引用一次。响应式编程让我们从目的地---也就是数据的订阅者开始,一路通过数据变形进行回溯,直到到达原始的数据依赖 - 可观察量 (observable)。通过这么做,数据管道的可观察量数据变形以及订阅者三者得以分离。
数据变形的部分是响应式编程所能带来的最大优势,但同时它也是学习曲线最为陡峭的部分。

2. RxSwift中的一些类型
  • Observable是一系列值的串流,我们可以对它们进行变形,订阅,或者将它们绑定到UI 元素上去。
  • PublishSubjectObservable 的一种,我们可以将值发送给它,这些值会被发给观察者。
  • BehaviorSubjectReplaySubjectPublishSubject 类似,不过我们可以在没有任何观察者连接上它时就进行值的发送,新的观察者会接收到暂存在 “重放” 缓冲区上的之前被发送的值。
  • DisposableDisposeBag 分别用来控制一个或多个订阅的生命周期。当一个Disposable 被销毁或者手动丢弃时,订阅行为就将结束,另外该订阅的所有的可观察量组成部分也将被释放。
3. RxSwift 中的部分变形函数
  • Map:映射
  • Filter:过滤
  • concat:将两个A、B两个Observable“串行”起来,在A发送onComplete前只会接受A的消息,A发送onComplete后才会接收B的消息。
  • Merge: 合并多个可观察序列,当其中一个发出消息时,会收到订阅回调。
  • taketake(whiletake(until等:控制订阅次数或根据触发条件订阅。
  • flatMapLatest:只保留flatMapLatest返回的最新一个Observable的订阅(flatMapLatest函数返回的是一个Observable)。

一个学习RxSwift的网站:https://www.hangge.com/blog/cache/category_72_1.html

三、一个双向绑定的例子

大多情况下,我们只需要单向绑定;但有时候可能会需要双向绑定,下面是一个双向绑定的示例:
登录页输入框要与VM的数据双向绑定

class ViewController: UIViewController {
    @IBOutlet weak var textField: UITextField!
    @IBOutlet weak var label: UILabel!
    var userVM = UserViewModel()
    let disposeBag = DisposeBag()
 
    override func viewDidLoad() {
        //将用户名与textField做双向绑定
        userVM.username.asObservable().bind(to: textField.rx.text).disposed(by: disposeBag)
        textField.rx.text.orEmpty.bind(to: userVM.username).disposed(by: disposeBag)
         
        //将用户信息绑定到label上
        userVM.userinfo.bind(to: label.rx.text).disposed(by: disposeBag)
    }
}

// 我们可以将双向绑定定义一个为一个操作符(官方demo中有这个文件,可拷贝)
// 上述中双向绑定的代码可以简化为:
//将用户名与textField做双向绑定
_ =  self.textField.rx.textInput <->  self.userVM.username

如果感兴趣的话,可以在RxSwift中的github上的样板工程:
https://github.com/ReactiveX/RxSwift


https://www.xamrdz.com/backend/3rf1935385.html

相关文章: