MVVM
来源:互联网 发布:电脑桌面软件怎么删除 编辑:程序博客网 时间:2024/05/02 04:43
目的:便于开发和维护代码
M(Model):数据模型
V(View + Controller): 展示内容 + 如何展示
VM(ViewModel):视图模型,处理展示的业务逻辑,包括按钮的点击,数据的请求和解析
登录功能实现
MVC实现:
#import "ViewController.h"#import "ReactiveCocoa.h"#import <MBProgressHUD/MBProgressHUD.h>@interface ViewController ()@property (weak, nonatomic) IBOutlet UITextField *usernameTextField;@property (weak, nonatomic) IBOutlet UITextField *pawwordTextField;@property (weak, nonatomic) IBOutlet UIButton *loginButton;@end@implementation ViewController- (void)viewDidLoad { // 字段校验(当用户名和密码都不为空的时候,登录按钮才可以点击)----------------------------------- RACSignal *validateFieldSignal = [RACSignal combineLatest:@[_usernameTextField.rac_textSignal, _pawwordTextField.rac_textSignal] reduce:^id(NSString *username, NSString *password){ return @(username.length && password.length); }]; RAC(_loginButton, enabled) = validateFieldSignal; // 按钮点击事件------------------------------------------ RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { NSLog(@"请求接口登录..."); return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSLog(@"发送响应的登录数据"); [subscriber sendNext:@"发送响应的登录数据"]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [subscriber sendCompleted]; }); return nil; }]; }]; [command.executionSignals.switchToLatest subscribeNext:^(id x) { NSLog(@"接收登录的数据"); }]; // 监听命令的执行过程 [[command.executing skip:1] subscribeNext:^(id x) { if ([x boolValue] == YES) { NSLog(@"正在登录ing..."); [MBProgressHUD showHUDAddedTo:self.view animated:YES]; } else { NSLog(@"登录完成!"); [MBProgressHUD hideHUDForView:self.view animated:YES]; } }]; [[_loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { NSLog(@"点击登录按钮"); [command execute:nil]; }]; }@end2016-12-18 11:08:32.704 ReactiveCocoa[47893:7242989] 点击登录按钮2016-12-18 11:09:10.111 ReactiveCocoa[47893:7242989] 请求接口登录...2016-12-18 11:09:13.871 ReactiveCocoa[47893:7242989] 正在登录ing...2016-12-18 11:11:58.765 ReactiveCocoa[47893:7242989] 发送响应的登录数据2016-12-18 11:12:02.722 ReactiveCocoa[47893:7242989] 接收登录的数据2016-12-18 11:12:07.418 ReactiveCocoa[47893:7242989] 登录完成!
代码分析:
1. 程序启动时就会执行聚合信号combineLatest:reduce:,结果是登录按钮不可点击
2. 当执行到创建命令RACCommand时,参数代码块和内部代码块都不执行
3. 当执行内部信号订阅时(command.executionSignals.switchToLatest),订阅的代码块也不执行
4. 命令的执行过程也不会得到执行(因为命令还没开始执行)
5. 按钮事件rac_signalForControlEvents:也不会执行(因为没有点击按钮)
6. 当每输入用户名和密码时都会执行聚合信号,来判断按钮是否可以点击(每当UITextField的文本发生改变,内部就会产生一个信号)
7. 单击登录按钮打印@”点击登录按钮”并执行命令([command execute:nil]),紧接着会执行初始化命令时传的代码块参数signalBlock, 也就打印NSLog(@”请求接口登录…”); 一但命令执行了,那么就会监听到命令的执行过程,接着订阅命令执行过程的代码块,打印NSLog(@”正在登录ing…”); 当signalBlock执行完时会返回一个信号RACSignal,也就是说会产生一个信号,那么从信号源中就能拿到返回的信号并订阅,(command.executionSignals.switchToLatest),一但订阅就会执行命令返回的信号中的代码块,接着打印NSLog(@”发送响应的登录数据”); ,当执行sendNext的时候会发送新号,接着打印NSLog(@”接收登录的数据”);, 当执行过sendCompleted时候就会打印NSLog(@”登录完成!”);
VM:处理界面上的所有业务逻辑,每一个控制器对应一个VM,VM中最好不要包括UI
MVVM实现:
#import <Foundation/Foundation.h>#import "ReactiveCocoa.h"@interface LoginViewModel : NSObject@property (strong, nonatomic) NSString *username;@property (strong, nonatomic) NSString *password;@property (strong, nonatomic, readonly) RACSignal *validateFieldSignal;@property (strong, nonatomic, readonly) RACCommand *loginCommand;@end#import "LoginViewModel.h"#import <MBProgressHUD/MBProgressHUD.h>@implementation LoginViewModel- (instancetype)init { if (self = [super init]) { [self setup]; } return self;}- (void)setup { _validateFieldSignal = [RACSignal combineLatest:@[RACObserve(self, username), RACObserve(self, password)] reduce:^id(NSString *username, NSString *password){ return @(username.length && password.length); }]; _loginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { NSLog(@"请求接口登录..."); return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSLog(@"发送响应的登录数据"); [subscriber sendNext:@"发送响应的登录数据"]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [subscriber sendCompleted]; }); return nil; }]; }]; [_loginCommand.executionSignals.switchToLatest subscribeNext:^(id x) { NSLog(@"接收登录的数据"); }]; // 监听命令的执行过程 [[_loginCommand.executing skip:1] subscribeNext:^(id x) { UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow; if ([x boolValue] == YES) { NSLog(@"正在登录ing..."); [MBProgressHUD showHUDAddedTo:keyWindow animated:YES]; } else { NSLog(@"登录完成!"); [MBProgressHUD hideHUDForView:keyWindow animated:YES]; } }];}@end
#import "ViewController.h"#import "LoginViewModel.h"#import "ReactiveCocoa.h"#import <MBProgressHUD/MBProgressHUD.h>@interface ViewController ()@property (weak, nonatomic) IBOutlet UITextField *usernameTextField;@property (weak, nonatomic) IBOutlet UITextField *pawwordTextField;@property (weak, nonatomic) IBOutlet UIButton *loginButton;@property (strong, nonatomic) LoginViewModel *loginViewModel;@end@implementation ViewController- (void)viewDidLoad { // 绑定值 RAC(self.loginViewModel, username) = _usernameTextField.rac_textSignal; RAC(self.loginViewModel, password) = _pawwordTextField.rac_textSignal; RAC(_loginButton, enabled) = self.loginViewModel.validateFieldSignal; // 处理事件 [[_loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { NSLog(@"点击登录按钮"); [self.loginViewModel.loginCommand execute:nil]; }];}- (LoginViewModel *)loginViewModel { if (_loginViewModel == nil) { _loginViewModel = [[LoginViewModel alloc] init]; } return _loginViewModel;}@end
RAC请求接口:
#import "ViewController.h"#import "RequestViewModel.h"#import "ReactiveCocoa.h"@interface ViewController ()@property (strong, nonatomic) RequestViewModel *requestViewModel;@end@implementation ViewController- (void)viewDidLoad { RACSignal *signal = [self.requestViewModel.requestCommand execute:nil]; [signal subscribeNext:^(id x) { NSLog(@"%@", x); }];}- (RequestViewModel *)requestViewModel { if (_requestViewModel == nil) { _requestViewModel = [[RequestViewModel alloc] init]; } return _requestViewModel;}@end
#import "ViewController.h"#import "RequestViewModel.h"#import "ReactiveCocoa.h"@interface ViewController ()@property (strong, nonatomic) RequestViewModel *requestViewModel;@end@implementation ViewController- (void)viewDidLoad { RACSignal *signal = [self.requestViewModel.requestCommand execute:nil]; [signal subscribeNext:^(id x) { NSLog(@"%@", x); }];}- (RequestViewModel *)requestViewModel { if (_requestViewModel == nil) { _requestViewModel = [[RequestViewModel alloc] init]; } return _requestViewModel;}@end#import <Foundation/Foundation.h>#import "ReactiveCocoa.h"@interface RequestViewModel : NSObject@property (strong, nonatomic) RACCommand *requestCommand;@end#import "RequestViewModel.h"#import <AFNetworking/AFNetworking.h>@implementation RequestViewModel- (RACCommand *)requestCommand { if (_requestCommand == nil) { _requestCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { RACSignal *requstSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; parameters[@"q"] = @"美女"; [manager GET:@"https://api.douban.com/v2/book/search " parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { [subscriber sendNext:responseObject[@"books"]]; } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { }]; return nil; }]; return requstSignal; }]; } return _requestCommand;}@end
- MVVM
- MVVM
- MVVM
- MVVM
- MVVM
- MVVM
- MVVM
- MVVM
- mvvm
- MVVM
- MVVM
- mvvm
- MVVM
- MVVM
- MVVM
- MVVM
- MVVM
- MVVM
- 微信小程序如何加载本地图片
- 抽象数据类型Triplet和ElemType的基本操作(8个)
- JavaEE – JPA(4):EntityManager相关核心概念
- Ubuntu14.04添加eclipse到桌面图标
- 做自己的module依赖库
- MVVM
- Redis Desktop Manager 0.8.8.384 远程连接(虚拟机)redis server
- Http協議詳解
- 生成静态页面的五种方案
- 作为首席架构师,我是如何选择并落地架构方案的?
- java原子操作
- gsoap 版本问题
- qt中MainWindow出现错误
- 安装MySQL最后一步时提示无响应解决方法