iOS技术分享iOS程序猿小知识点

利用RAC制作一个登录界面小Demo

2017-05-04  本文已影响968人  小冰山口
这里有一篇关于MVVM, 我觉得最好的解释说明:

MVVM 介绍

对于MVC架构, 即我们熟知的Model-View-Controller架构, 如下图所示:

MVC架构

M层请求数据, V层展示数据, C层处理逻辑. 但在实际开发过程中, C层和V层是偶联在一起的, 就形成了这种格局:

MVC架构

C层与M层交互, 这就往往会造成C层的逻辑过多, 代码臃肿.

这个时候, 就产生了MVVM架构, 即Model-View-ViewModel架构.即在C层和M层中间加了一个ViewModel层, ViewModel就是用来为C层瘦身的. 它的出现, 大大减少了控制器中的逻辑处理. 是C层变得轻巧.

MVVM架构

RAC在信号传递方面有着得天独厚的优势, 所以RAC+MVVM架构可以说是天作之合. 今天利用RAC写了一个登录界面, 把C层的逻辑处理抽出来放到了ViewModel层 :

登录界面的架构

C层拥有V层和VM层:

C层拥有V层和VM层

V层和VM层的数据交互放在C层处理:

V层和VM层的数据交互放在C层处理

这个小Demo没有Model, Model现在不直接与C层交互, 而是通过ViewModel.这样一来, 各个类之间各行其是:

步骤1: View层的数据通过C层给到VM层:

- (void)loginButtonEnable {
    RAC(self.loginViewModel, username) = _loginView.usernameTextField.rac_textSignal;
    RAC(self.loginViewModel, password) = _loginView.passwordTextField.rac_textSignal;
}

步骤2: VM层进行逻辑处理:

self.loginButtonEnableSignal = [RACSignal combineLatest:@[RACObserve(self, username), RACObserve(self, password)] reduce:^id(NSString *username, NSString *password){
        return @(username.length && password.length);
    }];

以上代码会返回一个包装了的BOOL值

步骤3: View层显示数据:

 RAC(self.loginView.loginButton, enabled) = _loginViewModel.loginButtonEnableSignal;

给button的enabled属性赋值, 告知按钮是否可以点击.

步骤1: View层的按钮响应点击事件, 并执行VM层的命令:

    [[_loginView.loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        [self.loginViewModel.loginCommad execute:nil];
    }];

步骤2: VM层创建命令:

self.loginCommad = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id input) {
        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/login"]];
            request.HTTPMethod = @"POST";
            NSString *paramString = [NSString stringWithFormat:@"username=%@&pwd=%@&type=JSON", self.username, self.password];
            NSData *paramData = [paramString dataUsingEncoding:NSUTF8StringEncoding];
            request.HTTPBody = paramData;
            [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                NSDictionary *resultDictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:NULL];
                [subscriber sendNext:resultDictionary];
                /****************** -------- 发送完成这一步很重要, 不然后面的无法信号无法执行 -------- ******************/
                [subscriber sendCompleted];
            }] resume];
            return nil;
        }];
    }];
    [self.loginCommad.executionSignals.switchToLatest subscribeNext:^(NSDictionary *x) {
        if ([x.allKeys.lastObject isEqualToString:@"success"]) {
            [SVProgressHUD showSuccessWithStatus:@"登录成功"];
            [SVProgressHUD dismissWithDelay:1 completion:^{
                YFFirstPageViewController *firstPageVC = [[YFFirstPageViewController alloc] init];
                [UIView animateWithDuration:1 animations:^{
                    [UIApplication sharedApplication].keyWindow.rootViewController = firstPageVC;
                }];
            }];
        }else {
            [SVProgressHUD showErrorWithStatus:@"登录失败"];
            [SVProgressHUD dismissWithDelay:1];
        }
    }];
    [[self.loginCommad.executing skip:1] subscribeNext:^(NSNumber * _Nullable x) {
        if ([x boolValue]) {
            [SVProgressHUD showWithStatus:@"正在登录中"];
        }
    }];

以上这些逻辑都是在VM层处理的.

在V层中, 我们只需要处理控件的布局即可, 而不需要处理任何逻辑事件:
控件的布局

这就是整个Demo的架构, 实现逻辑和代码, 效果如下:

Demo运行效果

+++++++++++++++Demo下载链接+++++++++++++++密码: nfx3

上一篇下一篇

猜你喜欢

热点阅读