参考:http://benbeng.leanote.com/post/ReactiveCocoaTutorial-part1
#import "LoginService.h"
@implementation LoginService
-(void) LoginWithUsername:(NSString *)username withPasswd:(NSString *)passwd complete:(MYResponseBlock)completeblock{
double delaySeconds = 2.0;
dispatch_time_t popTime=dispatch_time(DISPATCH_TIME_NOW, delaySeconds);
dispatch_after(popTime, dispatch_get_main_queue(), ^{
BOOL isSuccess = [username isEqualToString:@"user"]&&[passwd isEqualToString:@"1234"];
completeblock(isSuccess);
});
}
@end
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
#import "LoginService.h"
@interface ViewController ()<UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UITextField *userNameTextField;
@property (weak, nonatomic) IBOutlet UITextField *PasswdTextField;
@property (weak, nonatomic) IBOutlet UIButton *LoginBtn;
@property (strong ,nonatomic)LoginService *signInService;
@end
@implementation ViewController
//- (IBAction)LoginTap:(UIButton *)sender {
// NSLog(@"点击了登录按钮");
//
//}
- (void)viewDidLoad {
[super viewDidLoad];
self.signInService = [LoginService new];
/**
[self.userNameTextField.rac_textSignal subscribeNext:^(id x) {
NSLog(@"=%@",x);
}];//RACSignal发送事件流给它的subscriber(订阅者)
[[self.userNameTextField.rac_textSignal filter:^BOOL(id value) {
NSString *text = value;
return text.length > 3;
}]subscribeNext:^(id x) {
NSLog(@"==%@",x);
}];//当输入的字符超过3个时RACSignal发送事件
//上面的操作可以拆分为:
RACSignal *usernameSignal=self.userNameTextField.rac_textSignal;
RACSignal *filterednameSignal=[usernameSignal filter:^BOOL(id value) {
NSString *text = value;
return text.length > 3;
}];
[filterednameSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
//类型转换
[[self.userNameTextField.rac_textSignal filter:^BOOL(NSString *text) {
return text.length > 3;
}]subscribeNext:^(id x) {
NSLog(@"==%@",x);
}];//传入block的值肯定是个NSString,所以可以直接修改参数类型。
//使用map操作把接收的数据转换成想要的类型,只要它是一个对象
[[[self.userNameTextField.rac_textSignal map:^id(NSString *text) {
return @(text.length);
}]filter:^BOOL(NSNumber *length) {
return [length integerValue]>3;
}]subscribeNext:^(id x) {
NSLog(@"%@",x);
}];//map从上一个next事件接收数据,通过执行block把返回值传递给下一个next事件。map以NSString为输入,取字符串的长度,返回一个NSNumber
**/
RACSignal *validUsernameSignal=[self.userNameTextField.rac_textSignal map:^id(NSString * text) {
return @([self isValidUsername:text]);
}];
RACSignal *validPasswordSignal =[self.PasswdTextField.rac_textSignal map:^id(NSString * text) {
return @([self isValidPassword:text]);
}];
// [[validPasswordSignal map:^id(NSNumber *passwdValid) {
// return [passwdValid boolValue]?[UIColor clearColor]:[UIColor yellowColor];
// }]subscribeNext:^(UIColor * color) {
// self.PasswdTextField.backgroundColor=color;
// }];//不建议这样写,推荐下面写法:
RAC(self.PasswdTextField,backgroundColor)=[validPasswordSignal map:^id(NSNumber *passwdValid) {
return [passwdValid boolValue]?[UIColor clearColor]:[UIColor yellowColor];
}];//RAC宏允许直接把信号的输出应用到对象的属性上.RAC宏有两个参数,第一个是需要设置属性值的对象,第二个是属性名。每次信号产生的一个next事件,传递过来的值都会应用到该属性上。
RAC(self.userNameTextField,backgroundColor)=[validUsernameSignal map:^id(NSNumber *userNameValid) {
return [userNameValid boolValue]?[UIColor clearColor]:[UIColor yellowColor];
}];
//聚合信号
RACSignal *signUpActiveSignal = [RACSignal combineLatest:@[validPasswordSignal,validUsernameSignal] reduce:^id(NSNumber *usernameValid,NSNumber *passwdValid){
return @([usernameValid boolValue]&&[passwdValid boolValue]);
}];//reduce块的每个参数就是信号发出的内容。有多少信号组合,就有多少个参数
//http://cdn3.raywenderlich.com/wp-content/uploads/2014/01/CombinePipeline.png
[signUpActiveSignal subscribeNext:^(NSNumber * aa) {
self.LoginBtn.enabled = [aa boolValue];
if (self.LoginBtn.enabled) {
self.LoginBtn.backgroundColor=[UIColor greenColor];
}else{
self.LoginBtn.backgroundColor=[UIColor grayColor];
}
}];
[[[[self.LoginBtn rac_signalForControlEvents:UIControlEventTouchUpInside]
doNext:^(id x) {
self.LoginBtn.enabled = NO;
}]
flattenMap:^id(id value) {
return [self signInSignal];
}]
subscribeNext:^(NSNumber* x) {
BOOL success = [x boolValue];
if (success) {
[self performSegueWithIdentifier:@"HHH" sender:self];
}
}];//flattenMap方法实际上是根据前一个信号传递进来的参数重新建立了一个信号,这个,这个参数可能会在创建信号的时候用到,也有可能根本用不到。
//附加操作doNext,把按钮置为不可点击状态。并没有返回值,并不改变事件本身。
RACSignal *hhh=[self createSignal];
[hhh subscribeNext:^(id x) {
NSLog(@"aaaaaa");
}];//内部创建了一个订阅者(subscriber会执行自身的block即:“笑的不行了。”会打印)
[hhh subscribeNext:^(NSString *x) {
NSLog(@"bbbbbbb%@",x);//bbbbbbb调用所有订阅老子消息的订阅者的block
}];//内部创建了另一个订阅者(subscriber会执行自身的block)
}
-(RACSignal *)createSignal{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"笑的不行了。");
[subscriber sendNext:@"调用所有订阅老子消息的订阅者的block"];
NSLog(@"subscriber==%@",subscriber);
return nil;
}];
}
-(RACSignal *)signInSignal{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[self.signInService LoginWithUsername:self.userNameTextField.text withPasswd:self.PasswdTextField.text complete:^(BOOL success) {
[subscriber sendNext:@(success)];//发送一个next事件来表示登录是否成功
[subscriber sendCompleted];
}];
return nil;
}];
}
- (BOOL)isValidUsername:(NSString *)username {
return username.length > 3;
}
- (BOOL)isValidPassword:(NSString *)password {
return password.length > 3;
}