一、基本使用
1、RACTuple
- 同OC数组
① 初始化
RACTuple *tuple = [RACTuple tupleWithObjects:@"1", @"2", nil];
RACTuple *tupleFromArr = [RACTuple tupleWithObjectsFromArray:@[@"1", @"2"]];
RACTuple *tuplePack = RACTuplePack(@"1", @"2");
NSLog(@"%@ - %@ - %@", tuple[0], [tupleFromArr first], [tuplePack last]);
② 遍历
NSArray *arr = @[@"1", @"2", @"3"];
[arr.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"数组内容:%@", x);
}];
NSDictionary *dict = @{@"k1": @"v1", @"k2": @"v2"};
[dict.rac_sequence.signal subscribeNext:^(RACTuple * _Nullable x) {
RACTupleUnpack(NSString *key, NSString *value) = x;
NSLog(@"字典的key和value为%@, %@", key, value);
}];
③ 替换
NSArray *tempArr = @[@"1", @"2", @"3"];
NSArray *arr = [[tempArr.rac_sequence map:^id _Nullable(id _Nullable value) {
NSLog(@"数组内容:%@", value);
return @"0";
}] array]; // 方法一
NSArray *arr = [[tempArr.rac_sequence mapReplace:@"0"] array]; // 方法二
NSLog(@"%@", arr);
2UIButton
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(100, 100, 100, 100);
[btn setTitle:@"btnDemo" forState:UIControlStateNormal];
[btn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[self.view addSubview:btn];
[[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"%@按钮被点击了", x);
}];
3、UITextField
// 监听
// 监听输入,内容改变都会改
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
textField.placeholder = @"输入内容";
[[textField rac_textSignal] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"输入框输入内容为%@", x);
}];
[self.view addSubview:textField];
// 过滤
[[[textField rac_textSignal] filter:^BOOL(NSString * _Nullable value) {
return value.length>5;
}] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"输入框当前内容已超过5个字:%@", x);
}];
// 登录状态实时监听
UITextField *unameField = [[UITextField alloc] initWithFrame:CGRectMake(100, 100, 100, 44)];
unameField.placeholder = @"uname";
UITextField *passwordField = [[UITextField alloc] initWithFrame:CGRectMake(100, 160, 100, 44)];
passwordField.placeholder = @"pwd";
[self.view addSubview:unameField];
[self.view addSubview:passwordField];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(100, 240, 100, 10);
[btn setTitle:@"btnDemo" forState:UIControlStateNormal];
[btn setTitle:@"btnEnable" forState:UIControlStateDisabled];
[btn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[self.view addSubview:btn];
RAC(btn, enabled) = [RACSignal combineLatest:@[unameField.rac_textSignal, passwordField.rac_textSignal] reduce:^id _Nonnull{
return @(unameField.text.length && passwordField.text.length); // 用户名和密码都有输入的时候
}];
4、rac_signalForSelector(代替delegate)
[[self rac_signalForSelector:@selector(didReceiveMemoryWarning)] subscribeNext:^(RACTuple * _Nullable x) {
NSLog(@"调用didReceiveMemoryWarning");
}];
【Demo】
① 创建DemoView类,添加btn
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[btn setTitle:@"demoView上面的btn" forState:UIControlStateNormal];
btn.backgroundColor = [UIColor redColor];
[self addSubview:btn];
② DemoView类添加RACSubject类型属性
@property (nonatomic, strong) RACSubject *demoViewDelegate;
- (RACSubject *)demoViewDelegate {
if(_demoViewDelegate == nil) {
_demoViewDelegate = [RACSubject subject];
}
return _demoViewDelegate;
}
③ btn实现
[[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
[self.demoViewDelegate sendNext:@"点击了"];
[self clickDemoViewWithObject1:@"点了按钮" andObject2:@"测试传值"];
}];
- (void)clickDemoViewWithObject1:(NSString *)obj1 andObject2:(NSString *)obj2 {}
④ 创建demoView
DemoView *demoView = [[DemoView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
demoView.backgroundColor = [UIColor greenColor];
[self.view addSubview:demoView];
[demoView.demoViewDelegate subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
[[demoView rac_signalForSelector:@selector(clickDemoViewWithObject1:andObject2:)] subscribeNext:^(RACTuple * _Nullable x) {
NSLog(@"%@ - %@", x.first, x.second);
}];
5、RACObserve(代替KVO)
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
btn.backgroundColor = [UIColor redColor];
[self.view addSubview:btn];
[[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
x.frame = CGRectMake(200, 200, 50, 50);
}];
[RACObserve(btn, frame) subscribeNext:^(id _Nullable x) {
NSLog(@"替代KVO,监听btn的frame");
}];
6、两个
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(100, 100, 200, 44)];
textField.placeholder = @"输入框";
[self.view addSubview:textField];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 150, 200, 44)];
[self.view addSubview:label];
RAC(label, text) = textField.rac_textSignal;
二、一探究竟
1、RACSignal & RACDisposable
① RACSignal
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"创建信号量");
[subscriber sendNext:@"触发signal"];
return nil;
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"信号内容:%@", x);
}];
打印:RACDemo[8537:154025] 信号内容:发送信号
② RACDisposable
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"创建信号量");
[subscriber sendNext:@"触发signal"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"调用disposable");
}];
}];
RACDisposable *disposable = [signal subscribeNext:^(id _Nullable x) {
NSLog(@"信号内容:%@", x);
}];
NSLog(@"调用dispose前");
[disposable dispose];
NSLog(@"调用dispose后");
打印:
RACDemo[59019:726210] 创建信号量
RACDemo[59019:726210] 信号内容:触发signal
RACDemo[59019:726210] 调用disposable
RACDemo[59019:726210] 调用dispose前
RACDemo[59019:726210] 调用dispose后
2、RACSubject
RACSubject *subject = [RACSubject subject];
[subject sendNext:@"第一次send"];
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"第一次subscribe%:@", x);
}];
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"第二次subscribe:%@", x);
}];
[subject sendNext:@"第二次send"];
打印:
RACDemo[60384:752300] 第一次subscribe:第二次send
RACDemo[60384:752300] 第二次subscribe:第二次send
① RACSubject 与RACSignal关系
@interface RACSubject<ValueType> : RACSignal<ValueType> <RACSubscriber>
② RACSubject 与RACSignal方法调用区别
a. subscribeNext
其中,subscribe:实现
// RACSubject
NSMutableArray *subscribers = self.subscribers;
@synchronized (subscribers) {
[subscribers addObject:subscriber];
}
b. sendNext
// RACSubject
[self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
[subscriber sendNext:value];
}];
由上面demo可以看出:[subject sendNext:@“第一次send”];并没有调用,如何让它支持呢?
③ RACReplaySubject
a. 2种创建方式
// ①
RACReplaySubject *replySubject = [RACReplaySubject subject];
// ②
RACReplaySubject *replySubject = [RACReplaySubject replaySubjectWithCapacity:10];
b. replaySubjectWithCapacity:
RACReplaySubject *replySubject = [RACReplaySubject replaySubjectWithCapacity:2];
[replySubject sendNext:@"第一次send"];
[replySubject sendNext:@"第二次send"];
[replySubject subscribeNext:^(id _Nullable x) {
NSLog(@"subscribe:%@", x);
}];
[replySubject sendNext:@"第三次send"];
打印:
RACDemo[62140:784156] subscribe:第一次send
RACDemo[62140:784156] subscribe:第二次send
RACDemo[62140:784156] subscribe:第三次send
RACReplaySubject *replySubject = [RACReplaySubject replaySubjectWithCapacity:2];
[replySubject sendNext:@"第一次send"];
[replySubject sendNext:@"第二次send"];
[replySubject sendNext:@"第三次send"];
[replySubject subscribeNext:^(id _Nullable x) {
NSLog(@"subscribe:%@", x);
}];
[replySubject sendNext:@"第四次send"];
打印:
RACDemo[62269:786206] subscribe:第二次send
RACDemo[62269:786206] subscribe:第三次send
RACDemo[62269:786206] subscribe:第四次send
RACReplaySubject *replySubject = [RACReplaySubject replaySubjectWithCapacity:2];
[replySubject sendNext:@"第一次send"];
[replySubject sendNext:@"第二次send"];
[replySubject subscribeNext:^(id _Nullable x) {
NSLog(@"subscribe:%@", x);
}];
[replySubject sendNext:@"第三次send"];
[replySubject sendNext:@"第四次send"];
打印:
RACDemo[62331:787372] subscribe:第一次send
RACDemo[62331:787372] subscribe:第二次send
RACDemo[62331:787372] subscribe:第三次send
RACDemo[62331:787372] subscribe:第四次send
上面的三个demo为啥会有不一样的打印结果呢?
c. sendNext
- (void)sendNext:(id)value {
@synchronized (self) {
[self.valuesReceived addObject:value ?: RACTupleNil.tupleNil];
if (self.capacity != RACReplaySubjectUnlimitedCapacity && self.valuesReceived.count > self.capacity) {
[self.valuesReceived removeObjectsInRange:NSMakeRange(0, self.valuesReceived.count - self.capacity)];
}
[super sendNext:value];
}
}
d. subscribe
for (id value in self.valuesReceived) {
if (compoundDisposable.disposed) return;
[subscriber sendNext:(value == RACTupleNil.tupleNil ? nil : value)];
}
3、RACMulticastConnection
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"网络请求Request");
[subscriber sendNext:@"网络请求Response"];
return nil;
}];
RACMulticastConnection *multiConnect = [signal publish];
[multiConnect.signal subscribeNext:^(id _Nullable x) {
NSLog(@"第一次:%@", x);
}];
[multiConnect.signal subscribeNext:^(id _Nullable x) {
NSLog(@"第二次:%@", x);
}];
[multiConnect.signal subscribeNext:^(id _Nullable x) {
NSLog(@"第三次:%@", x);
}];
[multiConnect connect];
打印:
RACDemo[63248:801636] 网络请求Request
RACDemo[63248:801636] 第一次:网络请求Response
RACDemo[63248:801636] 第二次:网络请求Response
RACDemo[63248:801636] 第三次:网络请求Response
4、rac_liftSelector
RACSignal *signalOne = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"第一个signal"];
return nil;
}];
RACSignal *signalTwo = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"第二个signal"];
return nil;
}];
[self rac_liftSelector:@selector(sendWithFirstSignal:secondSignal:) withSignalsFromArray:@[signalOne, signalTwo]];
- (void)sendWithFirstSignal:(id)firstSignal secondSignal:(id)secondSignal {
NSLog(@"%@ - %@", firstSignal, secondSignal);
}
打印:RACDemo[51547:585335] 第一个signal - 第二个signal
5、RACCommand
从UIButton+RACCommandSupport.h:
@property (nonatomic, strong, nullable) RACCommand<__kindof UIButton *, id> *rac_command;
6、核心方法
① bind
RACSubject *subject = [RACSubject subject];
RACSignal *signal = [subject bind:^RACSignalBindBlock _Nonnull{
return ^RACSignal *(id _Nullable value, BOOL *stop) {
return [[RACSignal alloc] init];
};
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"收到的数据:%@", x);
}];
[subject sendNext:@"数据内容"];
② flattenMap & map
RACSubject *subject = [RACSubject subject];
[[subject flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
value = [NSString stringWithFormat:@"%@入坑RAC", value];
return [RACReturnSignal return:value]; // ①
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
[subject sendNext:@"what??"];
RACSubject *subject = [RACSubject subject];
[[subject map:^id _Nullable(id _Nullable value) {
return [NSString stringWithFormat:@"%@入坑RAC", value];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
[subject sendNext:@"what!!"];
两者有什么使用场景的优势区别呢?
【信号中的信号】
a. 双重订阅
RACSubject *subject1 = [RACSubject subject];
RACSubject *subject2 = [RACSubject subject];
[subject1 subscribeNext:^(id _Nullable x) {
NSLog(@"%@ - 啦啦啦", x);
[x subscribeNext:^(id _Nullable x) {
NSLog(@"%@ - 哈哈哈", x);
}];
}];
[subject1 sendNext:subject2];
[subject2 sendNext:@"信号中的信号"];
打印:
RACDemo[78276:1028896] <RACSubject: 0x6000025b1b80> name: - 啦啦啦
RACDemo[78276:1028896] 信号中的信号 - 哈哈哈
b. 订阅最新信号
RACSubject *subject1 = [RACSubject subject];
RACSubject *subject2 = [RACSubject subject];
[subject1.switchToLatest subscribeNext:^(id _Nullable x) {
NSLog(@"%@ - 啦啦啦", x);
}];
[subject1 sendNext:subject2];
[subject2 sendNext:@"信号中的信号"];
打印:
RACDemo[78376:1031008] 信号中的信号 - 啦啦啦
c. flattenMap
RACSubject *subject1 = [RACSubject subject];
RACSubject *subject2 = [RACSubject subject];
[[subject1 flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
return value;
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@ - 啦啦啦", x);
}];
[subject1 sendNext:subject2];
[subject2 sendNext:@"信号中的信号"];
打印:
RACDemo[78472:1032713] 信号中的信号 - 啦啦啦
③ filter
④ ignore & ignoreValues
RACSubject *subject = [RACSubject subject];
[[subject ignore:@"a"] subscribeNext:^(id _Nullable x) { // 如果用了[subject ignoreValues],则没有打印
NSLog(@"%@", x);
}];
[subject sendNext:@"我爱你哈哈哈a"];
[subject sendNext:@"hhhhh"];
[subject sendNext:@"a"];
打印:
RACDemo[78926:1044023] 我爱你哈哈哈a
RACDemo[78926:1044023] hhhhh
RACSubject *subject = [RACSubject subject];
[[[subject ignore:@"a"] ignore:@"hh"] subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
[subject sendNext:@"我爱你哈哈哈a"];
[subject sendNext:@"hh"];
[subject sendNext:@"a"];
打印:
RACDemo[79033:1046614] 我爱你哈哈哈a
⑤ take & takeLast & takeUntil
// 正序(X个)
RACSubject *subject = [RACSubject subject];
[[subject take:2] subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
[subject sendNext:@"a"];
[subject sendNext:@"b"];
[subject sendNext:@"c"];
打印:
RACDemo[79239:1051962] a
RACDemo[79239:1051962] b
// 倒序
RACSubject *subject = [RACSubject subject];
[[subject takeLast:2] subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
[subject sendNext:@"a"];
[subject sendNext:@"b"];
[subject sendNext:@"c"];
[subject sendCompleted];
打印:
RACDemo[79270:1053424] b
RACDemo[79270:1053424] c
RACSubject *subject = [RACSubject subject];
RACSubject *subject1 = [RACSubject subject];
[[subject takeUntil:subject1] subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
[subject1 subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
[subject sendNext:@"a"];
[subject sendNext:@"b"];
[subject1 sendNext:@"subject1"];
[subject sendNext:@"c"];
打印:
RACDemo[79485:1058387] a
RACDemo[79485:1058387] b
RACDemo[79485:1058387] subject1
⑥ distinctUntilChanged
// 连续相同的不打印
RACSubject *subject = [RACSubject subject];
[[subject distinctUntilChanged] subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
[subject sendNext:@"ab"];
[subject sendNext:@"ab"];
[subject sendNext:@"ab"];
[subject sendNext:@"a"];
[subject sendNext:@"ab"];
打印:
RACDemo[79675:1062747] ab
RACDemo[79675:1062747] a
RACDemo[79675:1062747] ab
可用的类型比较广
RACSubject *subject = [RACSubject subject];
[[subject distinctUntilChanged] subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
// 数组
[subject sendNext:@[@1]];
[subject sendNext:@[@1]];
// 字典
[subject sendNext:@{@"name": @"lemonior"}];
[subject sendNext:@{@"name": @"lemonior"}];
// 对象
UIView *view1 = [[UIView alloc] init];
view1.backgroundColor = [UIColor redColor];
UIView *view2 = [[UIView alloc] init];
view2.backgroundColor = [UIColor redColor];
[subject sendNext:view1];
[subject sendNext:view2];
打印:
RACDemo[79814:1066084] (
1
)
RACDemo[79814:1066084] {
name = lemonior;
}
RACDemo[79814:1066084] <UIView: 0x7fa93cf05d80; frame = (0 0; 0 0); layer = <CALayer: 0x6000006b8780>>
RACDemo[79814:1066084] <UIView: 0x7fa93cf06640; frame = (0 0; 0 0); layer = <CALayer: 0x6000006b87a0>>
7、RAC()和RACObserve()
RAC宏:
两种格式:
RAC_(TARGET, __VA_ARGS__, nil)
(RAC_(TARGET, __VA_ARGS__)
这个宏将一个信号流与一个对象的属性绑在一起,当这个 signal 有新的信号时即 next,这个 next 中的对象value将会被自动赋值到 target 的 keypath 中。第一种方法则带有 nilValue,这是在 next 中的对象value为 nil时,会被赋值给 target 的 keypath 的值。
三、扩展
1、RAC与MVVM
【附录】
1、文章汇总
2、ReactiveCocoa2实战
3、优雅的 RACCommand
4、RACCommand 在项目中的实战运用和理解
5、 -rac_signalForSelector: 的实现