ReactiveObjC

一、基本使用

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] 信号内容:发送信号

RACSignal

② 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;

区别RACCommand和RACSubject

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: 的实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值