MVVM + ReactiveCocoa 一些简单功能的实现

来源:互联网 发布:java泛型使用 编辑:程序博客网 时间:2024/06/05 06:03

1.介绍MVVM架构思想。

1.1 程序为什么要架构:便于程序员开发和维护代码。

1.2 常见的架构思想:

MVC M:模型 V:视图 C:控制器MVVM M:模型 V:视图+控制器 VM:视图模型MVCS M:模型 V:视图 C:控制器 C:服务类VIPER V:视图 I:交互器 P:展示器 E:实体 R:路由 (http://www.cocoachina.com/ios/20140703/9016.html)

1.3 MVVM介绍

模型(M):保存视图数据。视图+控制器(V):展示内容 + 如何展示视图模型(VM):处理展示的业务逻辑,包括按钮的点击,数据的请求和解析等等。

一个简单的例子:登录界面

/* 需求:1.监听两个文本框的内容,有内容才允许按钮点击    2.默认登录请求.用MVVM:实现,之前界面的所有业务逻辑分析:1.之前界面的所有业务逻辑都交给控制器做处理    2.在MVVM架构中把控制器的业务全部搬去VM模型,也就是每个控制器对应一个VM模型.步骤:1.创建LoginViewModel类,处理登录界面业务逻辑.    2.这个类里面应该保存着账号的信息,创建一个账号Account模型    3.LoginViewModel应该保存着账号信息Account模型。    4.需要时刻监听Account模型中的账号和密码的改变,怎么监听?    5.在非RAC开发中,都是习惯赋值,在RAC开发中,需要改变开发思维,由赋值转变为绑定,可以在一开始初始化的时候,就给Account模型中的属性绑定,并不需要重写set方法。    6.每次Account模型的值改变,就需要判断按钮能否点击,在VM模型中做处理,给外界提供一个能否点击按钮的信号.    7.这个登录信号需要判断Account中账号和密码是否有值,用KVO监听这两个值的改变,把他们聚合成登录信号.    8.监听按钮的点击,由VM处理,应该给VM声明一个RACCommand,专门处理登录业务逻辑.    9.执行命令,把数据包装成信号传递出去    10.监听命令中信号的数据传递    11.监听命令的执行时刻 */

控制器代码

 @interface ViewController ()@property (nonatomic, strong) LoginViewModel *loginViewModel;@property (weak, nonatomic) IBOutlet UITextField *accountField;@property (weak, nonatomic) IBOutlet UITextField *pwdField;@property (weak, nonatomic) IBOutlet UIButton *loginBtn;@end//- (LoginViewModel *)loginViewModel{if (_loginViewModel == nil) {    _loginViewModel = [[LoginViewModel alloc] init];}return _loginViewModel;}// 视图模型绑定//- (void)bindModel{// 给模型的属性绑定信号// 只要账号文本框一改变,就会给account赋值RAC(self.loginViewModel.account, account) = _accountField.rac_textSignal;RAC(self.loginViewModel.account, pwd) = _pwdField.rac_textSignal;// 绑定登录按钮RAC(self.loginBtn,enabled) = self.loginViewModel.enableLoginSignal;// 监听登录按钮点击[[_loginBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {    // 执行登录事件    [self.loginViewModel.LoginCommand execute:nil];}]; }

VM代码

@interface LoginViewModel : NSObject@property (nonatomic, strong) Account *account;// 是否允许登录的信号@property (nonatomic, strong, readonly) RACSignal *enableLoginSignal;@property (nonatomic, strong, readonly) RACCommand *LoginCommand;@end@implementation LoginViewModel//- (Account *)account{if (_account == nil) {    _account = [[Account alloc] init];}return _account;}//- (instancetype)init{if (self = [super init]) {    [self initialBind];}return self;}// 初始化绑定//- (void)initialBind  {// 监听账号的属性值改变,把他们聚合成一个信号。_enableLoginSignal = [RACSignal combineLatest:@[RACObserve(self.account, account),RACObserve(self.account, pwd)] reduce:^id(NSString *account,NSString *pwd){    return @(account.length && pwd.length);}];// 处理登录业务逻辑_LoginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {    NSLog(@"点击了登录");    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        // 模仿网络延迟        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{            [subscriber sendNext:@"登录成功"];            // 数据传送完毕,必须调用完成,否则命令永远处于执行状态            [subscriber sendCompleted];        });        return nil;    }];}];// 监听登录产生的数据[_LoginCommand.executionSignals.switchToLatest subscribeNext:^(id x) {    if ([x isEqualToString:@"登录成功"]) {        NSLog(@"登录成功");    }}];// 监听登录状态[[_LoginCommand.executing skip:1] subscribeNext:^(id x) {    if ([x isEqualToNumber:@(YES)]) {        // 正在登录ing...        // 用蒙版提示        [MBProgressHUD showMessage:@"正在登录..."];    }else    {        // 登录成功        // 隐藏蒙版        [MBProgressHUD hideHUD];    }}]; }
1 0
原创粉丝点击