一、基本使用
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、
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實戰