- (void)merge { 3 RACSubject *letters = [RACSubject subject]; 4 RACSubject *numbers = [RACSubject subject]; 5 RACSubject *chinese = [RACSubject subject]; 6 7 [[RACSignal 8 merge:@[letters, numbers, chinese]] 9 subscribeNext:^(id x) { , x); 11 }]; ]; ]; ]; 16 }
上面代码运行结果如下:
上面示例的原理图如下:
五. 在MVVM中引入RactiveCocoa
学以致用,最后来个简单的实例,来感受一下如何在MVVM中使用RactiveCocoa。当然今天RAC的应用是非常简单的,但原理就是这样的。接下啦我们要使用RAC模拟一下登录功能,当然,网络请求也是模拟的,这不是重点。重点在于如何在MVVM各层之间使用RAC的信号量来更方便的在各个层之间进行响应式数据交互。下面这个实例的UI是非常简单的,并且实现起来也是灰常简单的,关键还是在于RAC的应用。
1.搭建Demo所需UI,用户界面非常简单,公有两个用户界面,一个是登录页面(两个输入框,一个登录按钮),一个是登录后跳转的页面(一个展示用户名和密码的Label)。下方是使用Storyboard实现的用户登录页面。实现完后,个两个页面各自关联一个ViewContorller类。
2.下方是整个小Demo的工程目录,因为我们今天的重点是如何在MVVM中使用RAC, 所以重点在于RAC的应用,对于MVVM的分层就简化一些。下方有VC层,在VC层中有两个视图控制器,一个是登录使用的视图控制器(ViewContorller)另一个是登录成功后的视图控制器(LoginSuccessViewController)。而ViewModel中则是负责登录的ViewModel业务逻辑层,该层中负责数据验证,网络请求,数据存储等一些与UI无关的业务逻辑。
3.实现登录的ViewModel层
因为ViewModel层是独立于UI层而存在的,所以可以在没有UI的情况下我们就可以去实现相应模块的ViewModel层。这正好减少了个个层次间的耦合性,同时也提高了可测试性,总体上改善了可维护性。好废话少说,接下来要实现登录的ViewModel层。
(1) 登录ViewModel层对应的类的头文件中的内容如下所示(VCViewModel.h), 其实下方一些常用的信号量可以抽象出来放到ViewModel的父类中,这为了简化Demo没有做父类的抽象。下方就是VCViewModel中interface定义的公有属性和公有方法(Public)。userName和password(NSString类型) 用来绑定用户输入的用户名和密码。下方三个自定义信号量successObject, failureObject, errorObject 用来发送网络请求的数据。successObject负责处理网络请求成功且符合正常业务逻辑的事件, failureObject负责网络请求成功不符合正常业务逻辑的处理,errorObject负责网络异常处理。
VCViewModel.h 3 // ReactiveCocoaDemo Created by Mr.LuDashi on 15/10/19. 6 // Copyright © 2015年 ZeluLi. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 11 @interface VCViewModel : NSObject 12 @property (nonatomic, strong) NSString *userName; 13 @property (nonatomic, strong) NSString *password; 14 @property (nonatomic, strong) RACSubject *successObject; 15 @property (nonatomic, strong) RACSubject *failureObject; 16 @property (nonatomic, strong) RACSubject *errorObject; 17 18 - (id) buttonIsValid; 19 - (void)login; 20 @end
上面可能说的有些抽象,结合项目中的实例来解释一下什么时候发送successObject信号量,如何发送failureObject信号量,何时使用errorObject信号量。
以某些理财App中购买理财产品的业务流程为例。在用户下单之前先去判断用户是否实名认证以及绑定银行卡,如果用户已经实名和绑定银行卡就走正常支付流程(用户就是想去下单购买),VM就往VC发送successObject信号,当前VC就会根据信号量的指示跳转到下单支付页面。 但是如果用户没有实名或者绑卡,那么VM就给VC发送failureObject信号,根据信号量中的参数来判断是走实名认证流程还是走绑定银行卡流程。 errorObject就比较简单了,网络异常,后台服务器抛出的异常等不需要iOS这边做业务逻辑处理的,就放在errorObject中负责错误信息的展示。