前言
开始,要快
一、创建视图
image.png
二、ViewController中绑定视图和ViewModel
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *statuslabel;
@property (weak, nonatomic) IBOutlet UIImageView *iconImageView;
@property (weak, nonatomic) IBOutlet UITextField *accountTF;
@property (weak, nonatomic) IBOutlet UITextField *passwordTF;
@property (weak, nonatomic) IBOutlet UIButton *loginButton;
@property (nonatomic, strong) LoginViewModel *loginVM;
@end
@weakify(self);
//UI实时修改的值 传递给 --> vm
RAC(self.loginVM,account) = self.accountTF.rac_textSignal;
RAC(self.loginVM,password) = self.passwordTF.rac_textSignal;
// 按钮是否可点击
RAC(self.loginButton,enabled) = self.loginVM.loginEnableSignal;
// 响应的发送 -- 响应的接受 --- vm -- > UI (根据VM改变的值改变UI状态标签的值)
RAC(self.statuslabel,text) = self.loginVM.statusSubject;
[RACObserve(self.statuslabel, text) subscribeNext:^(id _Nullable x) {
if ([x isEqualToString:@"正在登录"]) {
[SVProgressHUD showWithStatus:x];
}else{
[SVProgressHUD dismiss];
}
}];
//监听loginVM中的iconUrl值变化改变UI的图片Icon
[RACObserve(self.loginVM, iconUrl) subscribeNext:^(id _Nullable x) {
@strongify(self);
self.iconImageView.image = [UIImage imageNamed:x];
}];
// vm ---> signal
[self.loginVM.loginEnableSignal subscribeNext:^(NSNumber *x) {
@strongify(self);
UIColor *color = (x.intValue == 0) ? [UIColor lightGrayColor] : [UIColor blueColor];
[self.loginButton setBackgroundColor:color];
}];
//监听按钮点击事件
[[self.loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
// ----> vm ---> 迁移
// 涉及 ---> 网络 ---> 状态 -- 响应 ---- 命令 ---vm ---> 请求网络
//loginCommand开始执行
[self.loginVM.loginCommand execute:@"开始登录"];
}];
三、ViewModel中处理获取的数据及根据业务逻辑创建不同信号
@interface LoginViewModel : NSObject
@property (nonatomic, copy) NSString *iconUrl;
@property (nonatomic, copy) NSString *account;
@property (nonatomic, copy) NSString *password;
@property (nonatomic, strong) RACSignal *loginEnableSignal;
@property (nonatomic, strong) RACCommand *loginCommand;
@property (nonatomic, strong) RACSubject *statusSubject;
@property (nonatomic) BOOL islogining;
@property (nonatomic,strong) LoginM *loginM;
@end
- (instancetype)init{
if (self = [super init]) {
// 绑定iconUrl的值由account的值改变而改变
RAC(self,iconUrl) = [[[RACObserve(self, account) skip:1] map:^id _Nullable(id _Nullable value) {
return [NSString stringWithFormat:@"www:%@",value];
}] distinctUntilChanged];
// 创建按钮是否能点击信号 --- account + password(都有值的话可以点击) --- 函数 组合+聚合
self.loginEnableSignal = [RACSignal combineLatest:@[RACObserve(self, account),RACObserve(self, password)] reduce:^id (NSString *account,NSString *password){
return @(account.length>0&&password.length>0);
}];
self.islogining = NO;
self.statusSubject = [RACSubject subject];
[self setupLoginCommand];
}
return self;
}
- (void)setupLoginCommand{
@weakify(self);
// 初始commadn
self.loginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
// 网络信号 --- 成功 -- 失败 -- 状态
NSLog(@"input === %@",input);
@strongify(self);
return [self.loginM loginRequest:self.account pwd:self.password];
}];
// 成功
[[self.loginCommand.executionSignals switchToLatest] subscribeNext:^(id _Nullable x) {
NSLog(@"switchToLatest == %@",x);
@strongify(self);
self.islogining = NO;
User *user = x[@"info"];
[self.statusSubject sendNext:[NSString stringWithFormat:@"登录成功-->%@",user.name]];
}];
// 失败
[self.loginCommand.errors subscribeNext:^(NSError * _Nullable x) {
NSLog(@"errors == %@",x);
@strongify(self);
self.islogining = NO;
[self.statusSubject sendNext:@"登录失败"];
}];
// 状态 一般是0-1-0(未执行-开始执行-结束) 所以跳过第一个信号
// [[self.loginCommand.executing skip:1] subscribeNext:^(NSNumber * _Nullable x) {
// NSLog(@"executing == %@",x);
// if ([x boolValue]) {
// [self statusLableAnimation];
// }
// }];
//第二种方式 直接忽略0
[[self.loginCommand.executing ignore:@(0)] subscribeNext:^(NSNumber * _Nullable x) {
@strongify(self);
if ([x boolValue]) {
[self statusLableAnimation];
}
}];
}
- (void)statusLableAnimation{
self.islogining = YES;
[self.statusSubject sendNext:@"正在登录"];
}
四、LoginM -- 提供数据
#import <Foundation/Foundation.h>
#import <ReactiveObjC.h>
@interface User : NSObject
@property (nonatomic,copy) NSString *account;
@property (nonatomic,copy) NSString *name;
@end
@interface LoginM : NSObject
- (RACSignal *)loginRequest:(NSString *)account pwd:(NSString *)pwd;
@end
#import "LoginM.h"
@implementation User
@end
@implementation LoginM
- (RACSignal *)loginRequest:(NSString *)account pwd:(NSString *)pwd{
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// 抽取 -- 网络
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if ([account isEqualToString:@"123"] && [pwd isEqualToString:@"123"]) {
User *user = [User new];
user.account = account;
user.name = @"小明";
[subscriber sendNext:@{@"info":user}]; // 序列化 --- [model class] -- @[model,model]
[subscriber sendCompleted];
}else{
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:100868 userInfo:@{@"LGError":@"fail"}];
[subscriber sendError:error];
}
});
return [RACDisposable disposableWithBlock:^{
NSLog(@"请求网络信号销毁了");
}];
}];
}
@end
五、总结
网友评论