美文网首页ReactiveCocoaSwift开发认知
Swift3+MVVM+ReactiveCocoa5实战1

Swift3+MVVM+ReactiveCocoa5实战1

作者: 蜜蜂6520 | 来源:发表于2017-05-01 11:07 被阅读722次

关于Swift3

14年苹果公司推出Swift语言,过程中语法不间断地变,后来Swift3大版本出来,语法稳定了很多。作者是从Swift3开始学习的,虽然可以继续使用oc,但作者认为Swift语言类型安全、语法优雅、集成了很多其他语言的优点、效率高,而且是苹果公司主推的开发语言,Apple Watch等只能用Swift语言开发,现在网上很多Demo基于Swift,不会怎么行。所以iOS程序员要与时俱进,Swift现在是必备技能,多对照学习下oc和Swift的不同写法就能互相转化。

关于MVVM

MVVM是iOS架构的一种。当然还有其它,比如我们经常使用的MVC和MVP。MVC有一个缺点就是时间长Controller会过于臃肿,走读困难、重构困难、单元测试困难,当然可以优化MVC。这里我们使用的替换架构是MVVM。
M:模型(包括数据Model和请求Model)
V:视图(包括Controller和View)
VM:视图模型(Controller中的业务逻辑)
可以实现高内聚低耦合。

关于ReactiveCocoa5

ReactiveCocoa5以下简称RAC5
要使用MVVM,可以自己使用Block,KVO,代理、通知的方式实现数据绑定,但与RAC5配合使用会方便很多。现在网上的RAC资料大多是基于RAC2.5 基于oc的,但是官方RAC已经更新到了RAC5 基于Swift。作者当然不愿意使用旧版本的,所以先从RAC2.5学习理论用法,再从RAC4中寻找Swift的使用方式,再结合官方github的英文文档,实现了简单的登录界面Demo分享给大家。
废话不多说。

Talk is cheap. Show me the code

需求描述:

登录界面,帐号和密码文本框只有它们都有值时,登录按钮启用,否则禁用置灰。
点击登录按钮,成功后打印登录成功

Model

class LoginDataModel: NSObject {

    var account:String = ""//帐号
    var pwd:String = ""//密码
    
}

ViewController

//这里插一句,导入RAC5,使用cocoapods
/*
platform :ios, '8.0'

target 'ReactiveCocoaDemo' do

  use_frameworks!

  pod 'ReactiveCocoa', '~> 5.0.0'

end
*/
// 使用RAC5要导入这3个模块
import ReactiveCocoa
import ReactiveSwift
import Result

class LoginViewController: UIViewController {
    
    lazy var loginViewModel = {
        return LoginViewModel()
    }()// 延迟加载,每一次使用时初始化
    
    @IBOutlet weak var accountTextField: UITextField!//storyboard的帐号控件
    @IBOutlet weak var pwdTextField: UITextField!//storyboard的帐号控件
    @IBOutlet weak var loginBtn: UIButton!//storyboard的登录按钮
    
    override func viewDidLoad() {
        super.viewDidLoad()

        bindModel()
    }

    func bindModel() {
        
        // 帐号控件内容同步到DataModel的帐号属性
        let accountProperty = DynamicProperty<String>(object: loginViewModel.loginDataModel,
                                               keyPath: #keyPath(LoginDataModel.account))
        accountProperty <~ accountTextField.reactive.continuousTextValues
        
        // 密码控件内容同步到DataModel的密码属性
        let pwdProperty = DynamicProperty<String>(object: loginViewModel.loginDataModel,
                                                      keyPath: #keyPath(LoginDataModel.pwd))
        pwdProperty <~ pwdTextField.reactive.continuousTextValues
        
        // 信号生成器的值同步到登录按钮的启用状态上
        loginBtn.reactive.isEnabled <~ loginViewModel.enableLoginProducer
        
    }
    
    @IBAction func login(_ sender: Any) {
        // 点击登录按钮,执行ViewModel的登录业务,观察结果并做出响应
        loginViewModel.loginAction.apply(()).start { (event) in
            switch event {
            case let .value(value):
                if value == "登录成功" {
                    print(value)
                }
            default:
                break
            }
        }
        
    }
}

ViewModel

import ReactiveCocoa
import ReactiveSwift
import Result

class LoginViewModel: NSObject {

    lazy var loginDataModel = {
        return LoginDataModel()
    }()
    
    var enableLoginProducer:SignalProducer<Bool,NoError>!// 信号生成器,登录按钮启用发送true,禁用发送false
    
    var loginAction:Action<(),String,AnyError>!//登录业务
    
    override init() {
        super.init()
        initialBind()
    }
    
    func initialBind() {
        
        // 监听DataModel帐号属性值变化
        let accountProducer = loginDataModel.reactive.values(forKeyPath: #keyPath(LoginDataModel.account))
        // 监听DataModel密码属性值变化
        let pwdProducer = loginDataModel.reactive.values(forKeyPath: #keyPath(LoginDataModel.pwd))
        // 当DataModel帐号和密码属性都不为空时,信号生成器发送true,否则发送false
        enableLoginProducer = SignalProducer.combineLatest(accountProducer, pwdProducer).map { (account,pwd) -> Bool in
            let accountStr = account as! String?
            let pwdStr = pwd as! String?
            let enabled = (accountStr != nil && accountStr?.characters.count != 0) && (pwdStr != nil && pwdStr?.characters.count != 0)
            return enabled
        }
        
        // 登录业务
        loginAction = Action<(),String,AnyError> { (_) -> SignalProducer<String, AnyError> in
            
            SignalProducer({ (observer, _) in
                observer.send(value: "登录成功")
                observer.sendCompleted()
            })
        }
        
    }
    
}

以上就是简单Demo的使用,忽略了网络请求,下一篇会有网络请求Demo

RAC5的学习资料

最快让你上手ReactiveCocoa之基础篇
ReactiveCocoa 4 官方文档翻译
官方GitHub资料

如果觉得我的文章对您有用,请点击喜欢。您的支持将鼓励我继续创作!

这是作者每一次写帖子,大家有什么不懂或我哪里写错了都可以评论留言,我一定会回复的~

相关文章

  • Swift3+MVVM+ReactiveCocoa5实战1

    关于Swift3 14年苹果公司推出Swift语言,过程中语法不间断地变,后来Swift3大版本出来,语法稳定了很...

  • Swift3+MVVM+ReactiveCocoa5实战2

    上一篇分享了登录界面,没有网络请求,着重理解下使用流程。这一篇给大家分享一下有网络请求的界面展示,Swift3+M...

  • Taro/微信小程序 swiper

    实战1: 实战2: 实战1: 实战2:

  • MySQL实战 目录

    MySQL实战 MySQL实战1 数据库概念介绍MySQL实战2 语法、筛选条件和函数MySQL实战3 分组查询和...

  • 实战1

    Tips: Q:调整浏览器宽窄时,发现只有header的文字动,背景图案不动是怎么回事? A:没有设置图片的bac...

  • 《文案堂》作品目录

    1.《实战写作》一本写作秘籍 每周一更新001【实战写作】(1)写作有多难?002【实战写作】(2)选题是门学问0...

  • 实战-MySQL定时增量备份(2)

    阅读本文大约需要 9 分钟 实战-MySQL定时全量备份(1) 实战-MySQL定时增量备份(2) 实战-将MyS...

  • 《Netty 实战》第1,2,3章

    传送门《Netty 实战》第1,2,3章 《Netty 实战》第4,5,6章 《Netty 实战》第7,8,9...

  • 《Netty 实战》第7,8,9章

    传送门《Netty 实战》第1,2,3章 《Netty 实战》第4,5,6章 《Netty 实战》第7,8,9...

  • 《Netty 实战》第12,13章

    传送门《Netty 实战》第1,2,3章 《Netty 实战》第4,5,6章 《Netty 实战》第7,8,9...

网友评论

    本文标题:Swift3+MVVM+ReactiveCocoa5实战1

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