美文网首页iOS-SDK开发
MVVM架构设计在iOS中的实践方式

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

作者: Sweet丶 | 来源:发表于2023-06-21 14:34 被阅读0次

    一、iOS的MVVM

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

    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

    相关文章

      网友评论

        本文标题:MVVM架构设计在iOS中的实践方式

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