本篇博客主要分析RAC 的基本使用 关于原理部分这里不再写,后边分析源码时会将相应的分析体会再做整理
信号产生 订阅 发送
形式 1
- (void)testSignalSend{
// 创建
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// 发送
[subscriber sendNext:@"数据来了"];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
}];
}];
// 订阅
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"---testSignalSend-----%@", x);
}];
}
形式 2
- (void)testRACSubject{
RACSubject *subject = [RACSubject subject];
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"-------%@", x);
}];
[subject sendNext:@"数据来了"];
}
控制层使用
- UIButton
- (void)testUIButton{
UIButton *racBtn = [UIButton buttonWithType:UIButtonTypeCustom];
racBtn.backgroundColor = [UIColor redColor];
[self.view addSubview:racBtn];
[racBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.view);
make.top.equalTo(self.mas_topLayoutGuide);
make.width.equalTo(@100);
make.height.equalTo(@50);
}];
[[racBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"点击了");
}];
}
- UITextField
- (void)testTextField{
UITextField *text = [[UITextField alloc]init];
text.frame = CGRectMake(120, 100, 100, 50);
[self.view addSubview:text];
[text.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
NSLog(@"----testTextField---%@",x);
}];
}
- KVO
- (void)testKVO{
[RACObserve(self, name) subscribeNext:^(id _Nullable x) {
NSLog(@"-------change---%@", x);
}];
}
- NSNotificationCenter
- (void)testNotification{
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"com.xiaobing.cn" object:nil] subscribeNext:^(NSNotification * _Nullable x) {
NSLog(@"----testNotification----%@", x);
}];
}
高阶函数
- filter
还拿UITextField举例
[[text.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
if (value.length > 6){
text.text = [value substringToIndex:6];
}
return value.length < 7;
}] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"----filter----%@", x);
}];
上边代码的结果是 文本框中最多输入6个字符 并且 只有满足长度小于7条件的时候 NSLog(@"----filter----%@", x); 才会执行
- flattenMap
还拿KVO 来举例
[[RACObserve(self, name) flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
return [RACReturnSignal return:[NSString stringWithFormat:@"给我多加一个 %@",value]];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"---RACReturnSignal------%@", x);
}];
上述代码输出的结果 就是 每一次name发生变化 都会拼接上 ”给我多加一个 “
- combineLatestWith 和 reduce
- (void)testCombineLastest{
[[RACSignal combineLatest:@[RACObserve(self, name), RACObserve(self, age)] reduce:^id (NSString *c1, NSNumber *c2){
return [NSString stringWithFormat:@"%@的年龄是 %d", c1, (int)c2.intValue];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"-----testCombineLastest---%@", x);
}];
}
combineLatestWith 将两个信号进行组合 reduce 是将两个值 进行合并输出
- takeUntil
- (void)testTakeUntil{
RACSubject *subject1 = [RACSubject subject];
RACSubject *subject2 = [RACSubject subject];
[[subject1 takeUntil:subject2] subscribeNext:^(id _Nullable x) {
NSLog(@"----takeUntil----%@", x);
}];
[subject1 sendNext:@"11"];
[subject1 sendNext:@"22"];
[subject2 sendCompleted];
[subject1 sendNext:@"33"];
}
解释 订阅的是subject1的信号 当 subject2 发送过 或者完成一个信号时 subject1的订阅就不再起作用了
- takeLast
- (void)testTakeLast{
RACSubject *subject = [RACSubject subject];
[[subject takeLast:2] subscribeNext:^(id _Nullable x) {
NSLog(@"----testTakeLast----%@", x);
}];
[subject sendNext:@"11"];
[subject sendNext:@"22"];
[subject sendNext:@"33"];
[subject sendNext:@"44"];
[subject sendCompleted];
}
解释 这里只会 接收到 33 44的回调 注意注意 这里必须调用 sendCompleted
MVVM 小试牛刀
实现功能就是 成语列表的展示 和 成员的审核
- 定义Model 类
@interface PeopleModel : NSObject
@property(nonatomic, copy)NSString *name;
@property(nonatomic, assign)int age;
@property(nonatomic, assign)BOOL isVerified;
@end
- 定义viewModel类
@class PeopleModel;
@interface PeopleViewModel : NSObject
@property(nonatomic, strong)NSMutableArray *peoples;
@property(nonatomic, strong)RACSubject *refreshSignal;
- (instancetype)init;
- (void)reloadData;
- (PeopleModel *)modelFromIndex:(NSInteger)index;
- (void)verifyPeople:(NSInteger)index;
- (NSString *)verifyStatus:(NSInteger)index;
@end
- 核心显示类
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *ident = @"cell";
MainCell *cell = [tableView dequeueReusableCellWithIdentifier:ident];
if(!cell){
cell = [[MainCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ident];
}
NSObject *peopleObj = (NSObject *)[self.peopleVM modelFromIndex:indexPath.row];
NSNumber *age = [peopleObj valueForKey:@"age"];
cell.nameLab.text = [peopleObj valueForKey:@"name"];
cell.detailLab.text = [NSString stringWithFormat:@"年龄是 %d", age.intValue];
[cell.verifiedBtn setTitle:[self.peopleVM verifyStatus:indexPath.row] forState:UIControlStateNormal];
@weakify(self)
[[cell.verifiedBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
@strongify(self)
[self.peopleVM verifyPeople:indexPath.row];
}];
return cell;
}
总结
个人觉得无论是MVC 还是MVVM 没有更好的架构 只有更合适的架构,首先第一点我们的数据Model层跟UI层肯定是不能有关联的,这就是所谓的解耦和,UI层不能引入Model ,这里有不少程序员包括我自己也写过把 Model直接传如Cell中 进行数据的配置,这样其实耦合度非常高,把数据的配置放在Controller的cellForRowAtIndexPath中去做 还勉强可以,毕竟C这一层就是控制数据显示的。但是苹果原生的Controller 貌似负责了很多东西,UITableView 也是UI层的东西 这里却放在了Controller中,个人觉的也不是很合适,那么如果把UITableView再单独封装到一个View中呢 又比较麻烦,所以我比较喜欢MVVM的模式,逻辑层单独抽离,把所有东西都变成输入和输出,用户的动作引起Model的改变是输入,Model改变后的结果就是输出,比如从待审核到审核状态。MVVM Controll就是一个完全的数据配置层了,整个功能中就只耦合了ViewModel 这一层。以上只是我的个人观点,大神们有不同观点可以一起探讨。