你的位置:首页 > 操作系统

[操作系统]ReactiveCocoa基础知识内容


本文记录一些关于学习ReactiveCocoa基础知识内容,对于ReactiveCocoa相关的概念如果不了解可以网上搜索;RACSignal有很多方法可以来订阅不同的事件类型,ReactiveCocoa框架使用category来为很多基本UIKit控件添加signal。

一:先创建页面布局(准备阶段)

@interface ViewController ()@property(strong,nonatomic)UITextField *nameTextField;@property(strong,nonatomic)UILabel *contentLabel;@property(strong,nonatomic)UIButton *saveBtn;@end

  if (self.nameTextField==nil) {    self.nameTextField=[[UITextField alloc]init];    self.nameTextField.backgroundColor=[UIColor grayColor];    [self.view addSubview:self.nameTextField];    [self.nameTextField mas_makeConstraints:^(MASConstraintMaker *make) {      make.top.mas_equalTo(self.view.mas_top).with.offset(64);      make.left.mas_equalTo(self.view.mas_left).with.offset(0);      make.right.mas_equalTo(self.view.mas_right).with.offset(0);      make.height.mas_equalTo(@40);    }];  }    if (self.contentLabel==nil) {    self.contentLabel=[[UILabel alloc]init];    self.contentLabel.backgroundColor=[UIColor blueColor];    [self.view addSubview:self.contentLabel];    [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {      make.top.mas_equalTo(self.nameTextField.mas_bottom).with.offset(10);      make.left.mas_equalTo(self.view.mas_left).with.offset(0);      make.right.mas_equalTo(self.view.mas_right).with.offset(0);      make.height.mas_equalTo(@100);    }];  }    if (self.saveBtn==nil) {    self.saveBtn=[[UIButton alloc]init];    self.saveBtn.backgroundColor=[UIColor blackColor];    [self.saveBtn setTitle:@"提交" forState:UIControlStateNormal];    [self.view addSubview:self.saveBtn];    [self.saveBtn mas_makeConstraints:^(MASConstraintMaker *make) {      make.top.mas_equalTo(self.contentLabel.mas_bottom).with.offset(20);      make.left.mas_equalTo(self.view.mas_left).with.offset(30);      make.right.mas_equalTo(self.view.mas_right).with.offset(-30);      make.height.mas_equalTo(@40);    }];  }

注意:saveBtn这个没有增加事件的调用代码,可以直接运用ReactiveCocoa给它注册事件,并把相应的操作绑定;

二:ReactiveCocoa小实例(控件创建完后直接把这些绑定在viewDidLoad中)

1:UITextField的rac_textSignal,它会在文本发生变化时产生信号

  [self.nameTextField.rac_textSignal subscribeNext:^(id x) {    self.contentLabel.text=x;  }];

 效果:输入马上会把变化的值显示出来;省去以前还要去监听的操作;

2:filter条件过滤

  [[self.nameTextField.rac_textSignal filter:^BOOL(id value) {    NSString *text=value;    return text.length>3;  }] subscribeNext:^(id x) {    self.contentLabel.text=x;  }];

效果:只有输入的字符串长度大于3才会显示出来,显示为字符串的内容;

3:拆分写法,rac_textSignalfilter都是RACSignal

  RACSignal *nameRacSignal=self.nameTextField.rac_textSignal;  RACSignal *filteredName=[nameRacSignal filter:^BOOL(id value) {    NSString *text=value;    return text.length>3;  }];  [filteredName subscribeNext:^(id x) {    self.contentLabel.text=x;  }];

效果:跟实例2上面的效果一样,只是分开定义;

4:上面所有的id类型都可以根据实际的情况进行类型对应

  [[self.nameTextField.rac_textSignal   filter:^BOOL(NSString *text){     return text.length > 3;   }]   subscribeNext:^(id x){     self.contentLabel.text=x;   }];

效果:这边filter里面为NSString类型;其它也可以相应的对照比如int bool等,效果如上

5:map 改变当前的值传给下个

  [[[self.nameTextField.rac_textSignal    map:^id(NSString *text){      return @(text.length);    }]   filter:^BOOL(NSNumber *length){     return [length intValue] > 3;   }]   subscribeNext:^(id x){     //记得转换显示 目前为NSNumber型     self.contentLabel.text=[NSString stringWithFormat:@"%@",x];   }];

效果:最后显示为:4,5,6,7,8,9.....,不会再显示字符串的内容,已经被map修改成length,所以filter参数也被改变了;运用可以用来转换成相要的对象

6:验证有效性,并把对应的属性进行修改(写法不好,见7点,宏定义RAC)

  RACSignal *validUsernameSignal =  [self.nameTextField.rac_textSignal   map:^id(NSString *text) {     return @([self isValidUsername:text]);   }];    [[validUsernameSignal   map:^id(NSNumber *userNameValid){     return[userNameValid boolValue] ? [UIColor redColor]:[UIColor yellowColor];   }]   subscribeNext:^(UIColor *color){     self.contentLabel.backgroundColor = color;   }];方法代码如下:-(BOOL)isValidUsername:(NSString *)userName{  if ([userName isEqualToString:@"wjy"]) {    return true;  }  else  {    return false;  }}

效果:只有当输入的字符串为wjy时才会改变背景效果;

7:宏RAC的运用

  RACSignal *validUsernameSignal =    [self.nameTextField.rac_textSignal     map:^id(NSString *text) {       return @([self isValidUsername:text]);     }];  RAC(self.contentLabel,backgroundColor)=[validUsernameSignal                      map:^id(NSNumber *userNameValid){                        return[userNameValid boolValue] ? [UIColor redColor]:[UIColor yellowColor];                      }];

效果:这种是简化的写法,直接用宏RAC进行,可以在目前的管道中移除subscribeNext:block,转而使用RAC宏

说明:RAC宏允许直接把信号的输出应用到对象的属性上。RAC宏有两个参数,第一个是需要设置属性值的对象,第二个是属性名。每次信号产生一个next事件,传递过来的值都会应用到该属性上。

8:聚合信号(引用)

RACSignal *validUsernameSignal = [self.usernameTextField.rac_textSignal map:^id(NSString *text) { return @([self isValidUsername:text]); }]; RACSignal *validPasswordSignal = [self.passwordTextField.rac_textSignal map:^id(NSString *text) { return @([self isValidPassword:text]); }];

RACSignal *signUpActiveSignal = [RACSignal combineLatest:@[validUsernameSignal, validPasswordSignal]          reduce:^id(NSNumber*usernameValid, NSNumber *passwordValid){           return @([usernameValid boolValue]&&[passwordValid boolValue]);          }];

[signUpActiveSignal subscribeNext:^(NSNumber*signupActive){  self.signInButton.enabled =[signupActive boolValue]; }];

说明:RACsignal的这个方法可以聚合任意数量的信号,reduce block的参数和每个源信号相关。ReactiveCocoa有一个工具类RACBlockTrampoline,它在内部处理reduce block的可变参数。

效果:上面的代码使用combineLatest:reduce:方法把validUsernameSignalvalidPasswordSignal产生的最新的值聚合在一起,并生成一个新的信号。每次这两个源信号的任何一个产生新值时,reduce block都会执行,block的返回值会发给下一个信号。

9:UIButton事件rac_signalForControlEvents

  [[self.saveBtn   rac_signalForControlEvents:UIControlEventTouchUpInside]   subscribeNext:^(id x) {     NSLog(@"button clicked");   }];

效果:点击事件响应

10:doNext

  [[[self.saveBtn   rac_signalForControlEvents:UIControlEventTouchUpInside]   doNext:^(id x) {     self.contentLabel.backgroundColor=[UIColor greenColor];   } ]   subscribeNext:^(id x) {     NSLog(@"button clicked");     self.contentLabel.backgroundColor=[UIColor redColor];   }];

说明doNext:是直接跟在按钮点击事件的后面。而且doNext: block并没有返回值。因为它是附加操作,并不改变事件本身,功能如:上面的doNext: block把按钮置为不可点击,隐藏登录失败提示。然后在subscribeNext: block里重新把按钮置为可点击,并根据登录结果来决定是否显示失败提示。实例如下

  实例:  [[[[self.saveBtn    rac_signalForControlEvents:UIControlEventTouchUpInside]    doNext:^(id x){      self.signInButton.enabled =NO;      self.signInFailureText.hidden =YES;    }]   flattenMap:^id(id x){     return[self signInSignal];   }]   subscribeNext:^(NSNumber*signedIn){     self.signInButton.enabled =YES;     BOOL success =[signedIn boolValue];     self.signInFailureText.hidden = success;     if(success){       [self performSegueWithIdentifier:@"signInSuccess" sender:self];     }   }];