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、

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

1、 -rac_signalForSelector: 的實現

① 傳遞多個信號

 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

三、問題集錦

  • RACSubject、RACSignal區別
  • sendNext:和subscribeNext區別
  • 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實戰

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章