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

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值