美文网首页
iOS架构篇-4 架构模式MVVM

iOS架构篇-4 架构模式MVVM

作者: 浪人残风 | 来源:发表于2021-03-11 16:53 被阅读0次

@[TOC](iOS架构篇-4 架构模式MVVM)

MVVM原理

image.png

MVVM(Model–View–Viewmodel)是一种软件架构模式。
View:页面UI、动画、控件、VC层,通常有UI控件、UI事件暴露出来
ViewModel:业务数据层,通常为View层持有,接受View层事件,绑定View层控件
Model:数据模型处理层,通常是网络接口请求,本地数据处理

MVVM 登录例子

下面以RXSwift框架结合登录功能具体说明整个流程:


image.png

View:

登录界面,账号 accountTxtField: UITextField、密码passwordTxtField: UITextField、消息提示msgLbl: UILabel、登录按钮loginBtn: UIButton

//
//  LoginVC.swift
//  ProjectApp
//
//  Created by jack on 2021/1/11.
//

import UIKit

class LoginVC: BaseVC {
    @IBOutlet weak var accountTxtField: UITextField!
    @IBOutlet weak var passwordTxtField: UITextField!
    @IBOutlet weak var loginBtn: UIButton!
    @IBOutlet weak var msgLbl: UILabel!
    
    var vm: LoginVM?
    let msgObservable: PublishSubject<String> =  PublishSubject<String>()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = "登录"

        // 传入账号、密码、登录按钮的事件监听
        self.vm = LoginVM(input: (account: accountTxtField.rx.text.orEmpty.asObservable(), password: passwordTxtField.rx.text.orEmpty.asObservable(), loginTap: loginBtn.rx.tap.asObservable()))
        
        // 登录按钮订阅ViewModel的signupEnabled属性,实时监听输入的账号、密码是否符合要求来判断登录按钮能否点击
        self.vm?.signupEnabled.subscribe(onNext: { [weak self](valid) in
            guard let self = self else { return }
            self.loginBtn.isEnabled = valid
            self.loginBtn.alpha = valid ? 1.0 : 0.5
        }, onError: { (error) in
            
        }, onCompleted: {
            
        }, onDisposed: {
            
        }).disposed(by: disposeBag)
        
        // 订阅ViewModel的loginResult属性,实时监听登录结果
        self.vm?.loginResult.subscribe(onNext: { [weak self](suc, errorMsg) in
            guard let self = self else { return }
            if suc { // 登录成功
                DPrint(message: "登录成功")
                self.msgObservable.onNext("登录成功")
            } else {// 账号/密码错误
                DPrint(message: "登录失败")
                self.msgObservable.onNext(errorMsg)
            }
        }, onError: { (e: Error) in
            // 网络出错、接口返回数据模型不对等异常情况回调
            DPrint(message: "登录失败:\(e.localizedDescription)")
        }, onCompleted: {
            
        }, onDisposed: {
            
        }).disposed(by: disposeBag)
        
        // 消息提示UILabel绑定
        self.msgObservable.bind(to: self.msgLbl.rx.text).disposed(by: disposeBag)
    }
}

ViewModel:

1.本地验证账号、密码
2.监听登录按钮
3.登录接口反馈

//
//  LoginVM.swift
//  ProjectApp
//
//  Created by jack on 2021/1/11.
//

import Foundation
class LoginVM {
    let validateAccount: Observable<Bool>
    let validatePassword: Observable<Bool>
    let signupEnabled: Observable<Bool>
    let loginResult: Observable<(Bool, String)>
   
    
    init(input:(
            account: Observable<String>,
            password: Observable<String>,
            loginTap: Observable<Void>
    )) {
        
        /// 验证账号
        validateAccount = input.account.flatMap({ (account) -> Observable<Bool> in
            var flag = true
            if account.count < 5 {
                flag = false
            }
            return Observable.of(flag)
        })
        
        /// 验证密码
        validatePassword = input.password.flatMap({ (password) -> Observable<Bool> in
            var flag = true
            if password.count < 5 {
                flag = false
            }
            return Observable.of(flag)
        })
        
        /// 有效账号&有效密码则可以点击登录按钮
        signupEnabled = Observable.combineLatest(validateAccount, validatePassword){
            accountFlag, passwordFlag in
            accountFlag && passwordFlag
        }.distinctUntilChanged()
        .share(replay: 1)
        
        /// 合并账号和密码,组成元组
        let accountAndPassword = Observable.combineLatest(input.account, input.password) { (account: $0, password: $1) }
        // 登录按钮点击事件
        self.loginResult = input.loginTap.withLatestFrom(accountAndPassword).flatMapLatest { (pair) -> Observable<RespEntity<User>> in
            let observable: Observable<RespEntity<User>> = rxrequest(params: .Login(account: pair.account, password: pair.password), errorToast: true, hud: true)
            return observable
        }
        /// 登录接口返回数据进行Observable转换
        .flatMap({ (resp: RespEntity<User>) -> Observable<(Bool, String)> in
            if let _ = resp.data { // 返回有用户数据则判断为登录成功
                // TODO 保存用户信息
                return Observable.of((true, ""))
            } else {
                var msg = "网络信号差,请稍后重试"
                if let str = resp.msg { // 如果返回有提示信息(如:账号错误、密码错误等)则提示返回的信息
                    msg = str
                }
                return Observable.of((false, msg))
            }
        })
    }
}

Model:

请求登录接口

相关文章

网友评论

      本文标题:iOS架构篇-4 架构模式MVVM

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