ReactiveCocoa入门(2)元祖、json解析、应用
3.3 元祖 RACTuple
什么叫做元祖?在 swift 中也有所谓的元祖,但是他跟 Objective-C 的数组有点不同。RAC的集合类
哪里不同呢?
- swift 中的元祖,他可以放进任何的数据类型!也就是说基本数据类型也能放进去。
- 但是 Objective-C 中的数组,它就只能放我们的 Objective-C 对象
- 而 RAC 的元祖,跟我们的 Objective-C 数组其实是一样的,换句话说,它其实就是封装了我们的 Objective-C 数组。
元祖
Swift 中的元祖,他可以装进任何类型的数据
OC 中的数组只能存放对象
RAC 中的元祖,封装了一层 OC 的数组
我们来个简单的元祖:
RACTuple * tuple1 = [RACTuple tupleWithObjectsFromArray:@[@"apple",@"google",@123]];
NSString * str = tuple1[0];
NSLog(@"%@",str);```
它的用法跟我们的数组是一模一样的。
取出它的第一个元素:`tuple1[0]`
说白了其实他就是一个数组~
元祖其实只是 RAC 中的一个集合类,他还有其他的集合类。我们来看看其他的集合类是什么样的?
![处理数组 - 遍历.png](https://img.haomeiwen.com/i1859446/6792e7843aa049b3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**数组遍历**
只要一行,全部搞定!是不是相对于for循环来说简单多了,主要是编程思想:链式编程、函数编程、响应式编程!
我们来分析一下这段代码,
前面`array.rac_sequence.signal` 这种连续的点,是练式编程,后面的x 在风里雨里一直等着你,是响应式编程,最后我们再把所有的操作放在block 里面一顿操作,是函数式编程!
一句代码三个愿望一次满足!
**处理字典**
![处理字典.png](https://img.haomeiwen.com/i1859446/b9ecf6a4469ba812.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
二话不说先将它转成集合,转成集合之后我们创建一个信号,创建信号之后我们订阅这个信号,然后把信号内容全部拿出来
![](https://img.haomeiwen.com/i1859446/bc417c232083cd99.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
他打印了两组数据,也就是两个元祖,每个园组里面分别是key 还有value .所以说x 他是一个id 任意类型,所以我们应该可以把它改成我们的元祖类型然后我们既然把x 当作元祖类型,是不是就是说我们可以用元组类型的方法来调用它?
那就需要用到RAC中的宏`RACTupleUnpack`,RAC里牛逼之一就有它的宏,可以进去学习下!
`Unpack` 就是解包的意思,我们来看看怎么去用这个解包的,首先我们要给他赋值,把我们的元祖丢给这个宏。然后在他的参数里面写上参数类型还有参数名字。
在这边其实就是key 跟value
`RACTupleUnpack(NSString * key, NSString * value) = x;`
然后接下来我们把这个key 跟value 打印出来。
![](https://img.haomeiwen.com/i1859446/0a5df30546bb09d2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
所以这边说明了~宏里面的参数其实就是需要被解析出来的变量名称!
**解析 json 数据**
首先创建个plist数据文件
![flags.plist.png](https://img.haomeiwen.com/i1859446/6951bb463631a54d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
第一步:建立模型
import <Foundation/Foundation.h>
@interface FLAGES : NSObject
@property(copy, nonatomic) NSString * name;
@property(copy, nonatomic) NSString * icon;
+(instancetype)flageWithDict:(NSDictionary *)dict;
@end
import "FLAGES.h"
@implementation FLAGES
+(instancetype)flageWithDict:(NSDictionary *)dict{
FLAGES * flages = [[FLAGES alloc]init];
[flages setValuesForKeysWithDictionary:dict];
return flages;
}
@end
第二步:回到我们的控制器 字典转模型
//3、应用
// RACSequence 他可以代替我们的数组,也可以代替字典
// 常用来解析 json 数据,最常使用的场合是 『字典转模型』
NSString * filePath = [[NSBundle mainBundle]pathForResource:@"flags.plist" ofType:nil];
NSArray * array2 = [NSArray arrayWithContentsOfFile:filePath];
//一般思维用法
// NSMutableArray * muArray = [NSMutableArray array];
// [array.rac_sequence.signal subscribeNext:^(NSDictionary * x) {
//
// //進行字典轉模型
// FLAGES * flages = [FLAGES flageWithDict:x];
// [muArray addObject:flages];
// }];
//升级版超爽用法
//value 集合里面所有的元素
NSArray * modelArray = [[array2.rac_sequence map:^id _Nullable(NSDictionary * value) {
return [FLAGES flageWithDict:value];
}]array];
NSLog(@"%@",modelArray);
// 我们自己定义了一个可变数组,然后再给他每次接收信号的时候把它转成对象放到术组里面去。
// 其实我们上下两边做的是一样的事情,此时此刻我们用了map 唯一的不同点是,他拿到了之后需要我们把这个对象给返回出去。因为它会自动帮我们把对象存到一个集合里面去。这个集合可以自动帮我们转成数组,因为它就是一个模型数组。
####常见应用
- 1、监听文本框
- 2、代替代理 RACSubject
- 3、代替 KVO
- 4、代替监听
- 5、代替通知
首先创建一个button,textFiled用作下面备用:
//1、监听文本框
[_textF.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
//2、代替代理 RACSubject (在第一篇中有说到RACSubject的使用,这个就是继承那个的使用方法)
[[_redView rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(RACTuple * _Nullable x) {
NSLog(@"%@",x);
}];
//3、代替 KVO
//导入#import "NSObject+RACKVOWrapper.h"
[[_btn rac_valuesForKeyPath:@"frame" observer:nil] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//4、代替监听
//把我们的点击事件当作信号
[[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"%@",x);
}];
//5、代替通知
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
NSLog(@"%@",x);
}];
####利用RAC做一个按钮倒计时
//
import "CountdownViewController.h"
import "ReactiveObjC.h"
@interface CountdownViewController ()
@property (nonatomic, assign) int time;
@property (nonatomic, strong) RACDisposable *disposable;
@end
@implementation CountdownViewController
-(IBAction)timeBtnClick:(UIButton *)sender {
sender.enabled = NO;
_time = 30;
//如果没有把 RACDisposable 强引用,RAC会给它自动转弱,执行一次完了
self.disposable = [[RACSignal interval:1.0 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) {
//更新UI 设置按钮上的文字
//1、time > 0 , 按钮上的时间倒计时
//2、time <= 0 , 按钮上显示【重新发送】
//感觉太low了 下面改进
// if (_time > 0) {
// sender.enabled = NO;
// [sender setTitle:[NSString stringWithFormat:@"%ds",_time] forState:UIControlStateNormal];
// }else{
// sender.enabled = YES;
// [sender setTitle:@"重新发送" forState:UIControlStateNormal];
//
// //关闭 timer (取消订阅)
// [_disposable dispose];
// }
NSString *btnTitle = _time > 0 ? [NSString stringWithFormat:@"%ds",_time] : @"重新发送";
[sender setTitle:btnTitle forState:UIControlStateNormal];
if (_time > 0) {
sender.enabled = NO;
}else{
sender.enabled = YES;
//关闭 timer (手动取消订阅)
[_disposable dispose];
}
_time --;
}];
//滑动scrollView,timer不受影响
}
-(void)dealloc{
//只有当倒计时结束了,才会dealloc
NSLog(@"我走了");
}
>上述代码可以到我的[GitHub](https://github.com/zpHao/ReactiveCocoa-primary)中下载
有错误,有问题的欢迎提出来!😊
*未完待续...*