RACSignal
RACSignal:
有数据产生的时候
,
就使用
RACSignal
RACSignal
使用步骤
: 1.
创建信号
2.
订阅信号
3.
发送信号
RACDisposable *(^didSubscribe)( id <RACSubscriber> subscriber) = ^RACDisposable *( id <RACSubscriber> subscriber) {
// didSubscribe 调用 : 只要一个信号被订阅就会调用
// didSubscribe 作用 : 发送数据
NSLog( @" 信号被订阅 " );
// 3. 发送数据
[subscriber sendNext: @1 ];
return nil ;
};
// 1. 创建信号 ( 冷信号 )
RACSignal *signal = [RACSignal createSignal:didSubscribe];
// 2. 订阅信号 ( 热信号 )
[signal subscribeNext:^( id x) {
// nextBlock 调用 : 只要订阅者发送数据就会调用
// nextBlock 作用 : 处理数据 , 展示到 UI 上面
// x: 信号发送的内容
NSLog( @"%@" ,x);
}];
// 只要订阅者调用 sendNext, 就会执行 nextBlock
// 只要订阅 RACDynamicSignal, 就会执行 didSubscribe
//
前提条件是
RACDynamicSignal,
不同类型信号
RACDisposable
@interface
ViewController
()
@property ( nonatomic , strong ) id <RACSubscriber> subscriber;
@end
@implementation ViewController
- ( void )viewDidLoad {
[ super viewDidLoad ];
// Do any additional setup after loading the view, typically from a nib.
// 1. 创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable *( id <RACSubscriber> subscriber ) {
@property ( nonatomic , strong ) id <RACSubscriber> subscriber;
@end
@implementation ViewController
- ( void )viewDidLoad {
[ super viewDidLoad ];
// Do any additional setup after loading the view, typically from a nib.
// 1. 创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable *( id <RACSubscriber> subscriber ) {
//系统会自动取消订阅者,这里被强引用,return 里不能取消订阅
_subscriber = subscriber;
// 3. 发送信号
[subscriber sendNext: @"123" ];
return [RACDisposable disposableWithBlock:^{
// 只要信号取消订阅就会来这
// 清空资源
NSLog( @" 信号被取消订阅了 " );
}];
}];
// 2. 订阅信号
RACDisposable *disposable = [signal subscribeNext:^( id x) {
NSLog( @"%@" ,x);
}];
// 1. 创建订阅者 , 保存 nextBlock
// 2. 订阅信号
// 默认一个信号发送数据完毕们就会主动取消订阅 .
// 只要订阅者在 , 就不会自动取消信号订阅
// 取消订阅信号
[disposable dispose];
// 3. 发送信号
[subscriber sendNext: @"123" ];
return [RACDisposable disposableWithBlock:^{
// 只要信号取消订阅就会来这
// 清空资源
NSLog( @" 信号被取消订阅了 " );
}];
}];
// 2. 订阅信号
RACDisposable *disposable = [signal subscribeNext:^( id x) {
NSLog( @"%@" ,x);
}];
// 1. 创建订阅者 , 保存 nextBlock
// 2. 订阅信号
// 默认一个信号发送数据完毕们就会主动取消订阅 .
// 只要订阅者在 , 就不会自动取消信号订阅
// 取消订阅信号
[disposable dispose];
}
RACSubject/RACReplaySubject
- (
void
)RACReplaySubject
{
// 1. 创建信号
RACReplaySubject *subject = [RACReplaySubject subject];
// 2. 订阅信号
[subject subscribeNext:^( id x) {
NSLog( @"%@" ,x);
}];
// 遍历所有的值 , 拿到当前订阅者去发送数据
// 3. 发送信号
[subject sendNext:@1];
{
// 1. 创建信号
RACReplaySubject *subject = [RACReplaySubject subject];
// 2. 订阅信号
[subject subscribeNext:^( id x) {
NSLog( @"%@" ,x);
}];
// 遍历所有的值 , 拿到当前订阅者去发送数据
// 3. 发送信号
[subject sendNext:@1];
// [subject sendNext:@1];
// RACReplaySubject
发送数据
:
// 1. 保存值
// 2. 遍历所有的订阅者 , 发送数据
// RACReplaySubject: 可以先发送信号 , 在订阅信号
}
- ( void )RACSubject
{
// 1. 创建信号
RACSubject *subject = [RACSubject subject];
// 2. 订阅信号
// 不同信号订阅的方式不一样
// RACSubject 处理订阅 : 仅仅是保存订阅者
[subject subscribeNext:^( id x) {
NSLog( @" 订阅者一接收到数据 :%@" ,x);
}];
// 3. 发送数据
[subject sendNext:@1];
// [subject subscribeNext:^(id x) {
// NSLog(@" 订阅二接收到数据 :%@",x);
// }];
// 保存订阅者
// 底层实现 : 遍历所有的订阅者 , 调用 nextBlock
// 执行流程 :
// RACSubject 被订阅 , 仅仅是保存订阅者
// RACSubject 发送数据 , 遍历所有的订阅 , 调用他们的 nextBlock
// 1. 保存值
// 2. 遍历所有的订阅者 , 发送数据
// RACReplaySubject: 可以先发送信号 , 在订阅信号
}
- ( void )RACSubject
{
// 1. 创建信号
RACSubject *subject = [RACSubject subject];
// 2. 订阅信号
// 不同信号订阅的方式不一样
// RACSubject 处理订阅 : 仅仅是保存订阅者
[subject subscribeNext:^( id x) {
NSLog( @" 订阅者一接收到数据 :%@" ,x);
}];
// 3. 发送数据
[subject sendNext:@1];
// [subject subscribeNext:^(id x) {
// NSLog(@" 订阅二接收到数据 :%@",x);
// }];
// 保存订阅者
// 底层实现 : 遍历所有的订阅者 , 调用 nextBlock
// 执行流程 :
// RACSubject 被订阅 , 仅仅是保存订阅者
// RACSubject 发送数据 , 遍历所有的订阅 , 调用他们的 nextBlock
}
集合
- (
void
)tuple
{
// 元组
RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[ @"213" , @"321" ,@1]];
NSString *str = tuple[0];
NSLog( @"%@" ,str);
{
// 元组
RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[ @"213" , @"321" ,@1]];
NSString *str = tuple[0];
NSLog( @"%@" ,str);
}
- (
void
)arr
{
// 数组
NSArray *arr = @[ @"213" , @"321" ,@1];
// RAC 集合
// RACSequence *sequence = arr.rac_sequence;
//
// // 把集合转换成信号
// RACSignal *signal = sequence.signal;
//
// // 订阅集合信号 , 内部会自动遍历所有的元素发出来
// [signal subscribeNext:^(id x) {
// NSLog(@"%@",x);
// }];
[arr.rac_sequence.signal subscribeNext:^( id x) {
NSLog( @"%@" ,x);
}];
{
// 数组
NSArray *arr = @[ @"213" , @"321" ,@1];
// RAC 集合
// RACSequence *sequence = arr.rac_sequence;
//
// // 把集合转换成信号
// RACSignal *signal = sequence.signal;
//
// // 订阅集合信号 , 内部会自动遍历所有的元素发出来
// [signal subscribeNext:^(id x) {
// NSLog(@"%@",x);
// }];
[arr.rac_sequence.signal subscribeNext:^( id x) {
NSLog( @"%@" ,x);
}];
}
- (
void
)dict
{
// 字典
NSDictionary *dict = @{ @"account" : @"aaa" , @"name" : @"xmg" , @"age" :@18};
// 转换成集合
[dict.rac_sequence.signal subscribeNext:^(RACTuple *x) {
// NSString *key = x[0];
// NSString *value = x[1];
// NSLog(@"%@ %@",key,value);
// RACTupleUnpack: 用来解析元组
// 宏里面的参数 , 传需要解析出来的变量名
// = 右边 , 放需要解析的元组
RACTupleUnpack(NSString *key,NSString *value) = x;
NSLog( @"%@ %@" ,key,value);
}];
{
// 字典
NSDictionary *dict = @{ @"account" : @"aaa" , @"name" : @"xmg" , @"age" :@18};
// 转换成集合
[dict.rac_sequence.signal subscribeNext:^(RACTuple *x) {
// NSString *key = x[0];
// NSString *value = x[1];
// NSLog(@"%@ %@",key,value);
// RACTupleUnpack: 用来解析元组
// 宏里面的参数 , 传需要解析出来的变量名
// = 右边 , 放需要解析的元组
RACTupleUnpack(NSString *key,NSString *value) = x;
NSLog( @"%@ %@" ,key,value);
}];
}
应用:数组转模型
Flag.h
@property
(
nonatomic
,
strong
)
NSString
*name;
@property ( nonatomic , strong ) NSString *icon;
@property ( nonatomic , strong ) NSString *icon;
+ (instancetype)flagWithDict:(NSDictionary *)dict;
Flag.m
+ (
instancetype
)flagWithDict:(
NSDictionary
*)dict
{
Flag *flag = [[ self alloc] init];
[flag setValuesForKeysWithDictionary:dict];
return flag;
{
Flag *flag = [[ self alloc] init];
[flag setValuesForKeysWithDictionary:dict];
return flag;
}
ViewController.m
- (
void
)viewDidLoad {
[ super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[ super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//
解析
plist
文件
NSString *filePath = [[ NSBundle mainBundle] pathForResource: @"flags.plist" ofType: nil ];
NSArray *dictArr = [ NSArray arrayWithContentsOfFile:filePath];
// NSMutableArray *arr = [NSMutableArray array];
// [dictArr.rac_sequence.signal subscribeNext:^(NSDictionary *x) {
// Flag *flag = [Flag flagWithDict:x];
// [arr addObject:flag];
// }];
// 高级用法
// 会把集合中所有元素都映射成一个新的对象
NSArray *arr = [[dictArr.rac_sequence map:^ id (NSDictionary *value) {
// value: 集合中元素
// id: 返回对象就是映射的值
return [Flag flagWithDict:value];
}] array];
NSLog( @"%@" ,arr);
NSString *filePath = [[ NSBundle mainBundle] pathForResource: @"flags.plist" ofType: nil ];
NSArray *dictArr = [ NSArray arrayWithContentsOfFile:filePath];
// NSMutableArray *arr = [NSMutableArray array];
// [dictArr.rac_sequence.signal subscribeNext:^(NSDictionary *x) {
// Flag *flag = [Flag flagWithDict:x];
// [arr addObject:flag];
// }];
// 高级用法
// 会把集合中所有元素都映射成一个新的对象
NSArray *arr = [[dictArr.rac_sequence map:^ id (NSDictionary *value) {
// value: 集合中元素
// id: 返回对象就是映射的值
return [Flag flagWithDict:value];
}] array];
NSLog( @"%@" ,arr);
}
使用场景
代理(对比)
方法一 RACSubject(可传值):
DDCarTypeCell.h
@protocol
CarTypeDelegate <
NSObject
>
- ( void )changeTaxiCostLabelWithZoomLevel:( NSUInteger )zoomLevel;
- ( void )changeTaxiCostLabelWithZoomLevel:( NSUInteger )zoomLevel;
@end
@interface
DDCarTypeCell :
UITableViewCell
@property
(
nonatomic
,
assign
)
id
<
CarTypeDelegate
>delegate;
reactiveCocoa
@property
(
nonatomic
,
strong
) RACSubject *btnClickSignal;
@end
DDCarTypeCell.m
- (
instancetype
)initWithCoder:(
NSCoder
*)aDecoder{
self = [ super initWithCoder:aDecoder];
self = [ super initWithCoder:aDecoder];
if([_delegaterespondsToSelector:@selector(changeTaxiCostLabelWithZoomLevel:)]) {
[
_delegate
changeTaxiCostLabelWithZoomLevel
:16];
}
reactiveCocoa
[
self
sendNext:@16
];
return
self
;
}
}
reactiveCocoa
- (RACSubject *)btnClickSignal
{
if (_btnClickSignal == nil ) {
_btnClickSignal = [RACSubject subject];
}
return _btnClickSignal;
}
{
if (_btnClickSignal == nil ) {
_btnClickSignal = [RACSubject subject];
}
return _btnClickSignal;
}
ViewController.m
@interface
DDTaxiViewController () <CarTypeDelegate>
- (
void
)viewDidLoad {
[ super viewDidLoad];
[ super viewDidLoad];
UITableViewCell *cell = [UITableViewCell alloc] init];
cell.delegate = self;
reactiveCocoa
//
订阅信号
[cell.btnClickSignal subscribeNext:^(id
x) {
NSLog( @"%@" ,x);
}];
}
#pragma mark - carType delegate
- ( void )changeTaxiCostLabelWithZoomLevel:( NSUInteger )zoomLevel{
- ( void )changeTaxiCostLabelWithZoomLevel:( NSUInteger )zoomLevel{
}
方法二 rac_signalForSelector(不需传值):
RedVIew.h
//私有方法
- (
IBAction
)btnClick:(
id
)sender
{
// NSLog(@" 按钮被点击 l");
{
// NSLog(@" 按钮被点击 l");
//
通知控制器做事情
}
ViewController.m
@property
(
weak
,
nonatomic
)
IBOutlet
RedVIew *redView;
@property (weak,nonatomic)IBOutletUIButton *btn;
@property (weak,nonatomic)IBOutletUIButton *btn;
@property
(
weak
,
nonatomic
)
IBOutlet
UITextField *textField;
- (
void
)delegate
{
// 1. 代替代理 :1.RACSubject 2.rac_signalForSelector
// 只要传值 , 就必须使用 RACSubject
[[_redView rac_signalForSelector: @selector (btnClick:)] subscribeNext:^( id x) {
NSLog( @" 控制器知道按钮被点击 " );
}];
// RAC:
// 把控制器调用 didReceiveMemoryWarning 转换成信号
// rac_signalForSelector: 监听某对象有没有调用某方法
// [[self rac_signalForSelector:@selector(didReceiveMemoryWarning)] subscribeNext:^(id x) {
// NSLog(@" 控制器调用 didReceiveMemoryWarning");
// }];
// 1. 代替代理 :1.RACSubject 2.rac_signalForSelector
// 只要传值 , 就必须使用 RACSubject
[[_redView rac_signalForSelector: @selector (btnClick:)] subscribeNext:^( id x) {
NSLog( @" 控制器知道按钮被点击 " );
}];
// RAC:
// 把控制器调用 didReceiveMemoryWarning 转换成信号
// rac_signalForSelector: 监听某对象有没有调用某方法
// [[self rac_signalForSelector:@selector(didReceiveMemoryWarning)] subscribeNext:^(id x) {
// NSLog(@" 控制器调用 didReceiveMemoryWarning");
// }];
}
kvo
好处:高聚合,添加观察和改变执行的方法在一起,并且不用判断监听的值
ViewController.m
需要引入头
#import
"NSObject+RACKOVWrapper.h"
[_redView rac_observeKeyPath:
@"frame"
options:NSKeyValueObservingOptionNew observer:
nil
block:^(
id
value, NSDictionary *change,
BOOL
causedByDealloc,
BOOL
affectedOnlyLastComponent) {
}];
[_redView rac_observeKeyPath:
@"bounds"
options:NSKeyValueObservingOptionNew observer:
nil
block:^(
id
value, NSDictionary *change,
BOOL
causedByDealloc,
BOOL
affectedOnlyLastComponent) {
}];
[[_redView rac_valuesForKeyPath:@"frame" observer:nil] subscribeNext:^(id x) {
// x:
修改的值
NSLog(
@"%@"
,x);
}];
}];
监听事件
[[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(
id
x) {
NSLog( @" 按钮点击了 " );
NSLog( @" 按钮点击了 " );
}];
代替通知
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:
nil
] subscribeNext:^(
id
x) {
NSLog( @"%@" ,x);
NSLog( @"%@" ,x);
}];
监听文本框
[_textField.rac_textSignal subscribeNext:^(
id
x) {
NSLog( @"%@" ,x);
NSLog( @"%@" ,x);
}];
处理当界面有多次请求时,需要都获取到数据时,才能展示界面
- (
void
)liftSelector
{
// 当一个界面有多次请求时候 , 需要保证全部都请求完成 , 才搭建界面
// 请求热销模块
RACSignal *hotSignal = [RACSignal createSignal:^RACDisposable *( id <RACSubscriber> subscriber) {
// 请求数据
// AFN
NSLog( @" 请求数据热销模块 " );
[subscriber sendNext: @" 热销模块的数据 " ];
return nil ;
}];
// 请求最新模块
RACSignal *newSignal = [RACSignal createSignal:^RACDisposable *( id <RACSubscriber> subscriber) {
// 请求数据
NSLog( @" 请求最新模块 " );
[subscriber sendNext: @" 最新模块数据 " ];
return nil ;
}];
// 数组 : 存放信号
// 当数组中的所有信号都发送数据的时候 , 才会执行 Selector
// 方法的参数 : 必须跟数组的信号一一对应
// 方法的参数 ; 就是每一个信号发送的数据
[ self rac_liftSelector: @selector (updateUIWithHotData:newData:) withSignalsFromArray:@[hotSignal,newSignal]];
}
- ( void )updateUIWithHotData:( NSString *)hotData newData:( NSString *)newData
{
// 拿到请求的数据
NSLog( @" 更新 UI %@ %@" ,hotData,newData);
{
// 当一个界面有多次请求时候 , 需要保证全部都请求完成 , 才搭建界面
// 请求热销模块
RACSignal *hotSignal = [RACSignal createSignal:^RACDisposable *( id <RACSubscriber> subscriber) {
// 请求数据
// AFN
NSLog( @" 请求数据热销模块 " );
[subscriber sendNext: @" 热销模块的数据 " ];
return nil ;
}];
// 请求最新模块
RACSignal *newSignal = [RACSignal createSignal:^RACDisposable *( id <RACSubscriber> subscriber) {
// 请求数据
NSLog( @" 请求最新模块 " );
[subscriber sendNext: @" 最新模块数据 " ];
return nil ;
}];
// 数组 : 存放信号
// 当数组中的所有信号都发送数据的时候 , 才会执行 Selector
// 方法的参数 : 必须跟数组的信号一一对应
// 方法的参数 ; 就是每一个信号发送的数据
[ self rac_liftSelector: @selector (updateUIWithHotData:newData:) withSignalsFromArray:@[hotSignal,newSignal]];
}
- ( void )updateUIWithHotData:( NSString *)hotData newData:( NSString *)newData
{
// 拿到请求的数据
NSLog( @" 更新 UI %@ %@" ,hotData,newData);
}