登陆页面实现
普通MVC的处理方式,是所有的业务逻辑都交给控制器处理 在MVVM 架构中把控制吕的业务全部搬去VM模型,也就是每个控制器对应一个VM模型。
1. 控制器中初始化LoginViewModel并进行绑定
- (LoginViewModel *)loginViewModel{
if (!_loginViewModel) {
_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];
}];
}
2. VC 中处理相应逻辑
@interface LoginViewModel : NSObject
@property (nonatomic, strong) Account *account;
@property (nonatomic, strong, readonly) RACSignal *enableLoginSignal;
@property (nonatomic, strong, readonly) RACCommand *loginCommand;
@end
初始化VM 时进行绑定
- (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.executionSignals.switchToLatest subscribeNext:^(id x) {
if ([x isEqualToString:@"登录成功"]) {
NSLog(@"登录成功");
}
}];
// 监听登录状态
[[_LoginCommand.executing skip:1] subscribeNext:^(id x) {
if ([x isEqualToNumber:@(YES)]) {
[MBProgressHUD showMessage:@"正在登录..."];
}else{
[MBProgressHUD hideHUD];
}
}];
}
- (RACCommand*)loginCommand{
if(!_loginCommand){
_loginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
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;
}];
}];
return _loginCommand;
}
信号合并处理
combineLatest 将多个信号合并起来,并且拿到各个信号的最新的值,必须每个合并的signal至少都有过一次sendNext,才会触发合并的信号(combineLatest 与 zipWith不同的是,每次只拿各个信号最新的值)
RAC(self.sureBtn,enabled) =
[RACSignal combineLatest:@[RACObserve(self.viewModel,name),RACObserve(self.viewModel, pwd)]
reduce:^(NSString *name, NSString *pwd){
if (pwd.length > 0 && name.length > 0) {
self.sureBtn.backgroundColor = UIColor.redColor;
return @(YES);
}else{
self.sureBtn.backgroundColor = UIColor.systemGrayColor;
return @(NO);
}
}];
网络请求
控制器会提供一个请求的VM,处理界面的业务逻辑
1. 控制器中初始化RequestViewModel
- (RequestViewModel *)requesViewModel{
if (!_requesViewModel) {
_requesViewModel = [[RequestViewModel alloc] init];
}
return _requesViewModel;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.dataSource = self.requesViewModel;
// 执行请求
RACSignal *requesSiganl = [self.requesViewModel.reuqesCommand execute:nil];
// 获取请求的数据
[requesSiganl subscribeNext:^(NSArray *x) {
self.requesViewModel.models = x;
[self.tableView reloadData];
}];
}
2. 视图模型
@interface RequestViewModel : NSObject<UITableViewDataSource>
// 请求命令
@property (nonatomic, strong, readonly) RACCommand *reuqesCommand;
//模型数组
@property (nonatomic, strong, readonly) NSArray *models;
@end
- (void)initialBind{
_reuqesCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
//初始化信号
RACSignal *requestSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
parameters[@"q"] = @"基础";
// 发送请求
[[AFHTTPRequestOperationManager manager] GET:@"xxx" parameters:parameters success:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) {
[subscriber sendNext:responseObject];
[subscriber sendCompleted];
} failure:^(AFHTTPRequestOperation * _Nonnull operation, NSError * _Nonnull error) {
}];
return nil;
}];
// 在返回数据信号时,把数据中的字典映射成模型信号,传递出去
return [requestSignal map:^id(NSDictionary *value) {
NSMutableArray *dictArr = value[@"books"];
// 字典转模型,遍历字典中的所有元素,全部映射成模型,并且生成数组
NSArray *modelArr = [[dictArr.rac_sequence map:^id(id value) {
return [Book bookWithDict:value];
}] array];
return modelArr;
}];
}];
}
#pragma mark - UITableViewDataSource
...