上篇RAC入門的文章相信大家都已經比較了解了,下面就給大家介紹RAC比較高級的東西。
1.創建信號
// RACSignal使用步驟:
// 1.創建信號 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
// 2.訂閱信號,才會激活信號. - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// 3.發送信號 - (void)sendNext:(id)value
// RACSignal底層實現:
// 1.創建信號,首先把didSubscribe保存到信號中,還不會觸發。
// 2.當信號被訂閱,也就是調用signal的subscribeNext:nextBlock
// 2.2 subscribeNext內部會創建訂閱者subscriber,并且把nextBlock保存到subscriber中。
// 2.1 subscribeNext內部會調用siganl的didSubscribe
// 3.siganl的didSubscribe中調用[subscriber sendNext:@1];
// 3.1 sendNext底層其實就是執行subscriber的nextBlock
// 1.創建信號
RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// block調用時刻:每當有訂閱者訂閱信號,就會調用block。
// 2.發送信號
[subscriber sendNext:@1];
// 如果不在發送數據,最好發送信號完成,內部會自動調用[RACDisposable disposable]取消訂閱信號。
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
// block調用時刻:當信號發送完成或者發送錯誤,就會自動執行這個block,取消訂閱信號。
// 執行完Block后,當前信號就不在被訂閱了。
NSLog(@"信號被銷毀");
}];
}];
// 3.訂閱信號,才會激活信號.
[siganl subscribeNext:^(id x) {
// block調用時刻:每當有信號發出數據,就會調用block.
NSLog(@"接收到數據:%@",x);
}];
2.信號的處理:
filter:過濾前綴包含“mei”的字符串
[[mytextField.rac_textSignal filter:^BOOL(NSString *value) {
return [value hasPrefix:@"mei"];
}] subscribeNext:^(NSString *value) {
NSLog(@"This value has prefix `mei` : %@", value);
}];
ignore:忽略前綴包含“mei”的字符串
[[mytextField.rac_textSignal ignore:@"mei"] subscribeNext:^(NSString *value) {
NSLog(@"`mei` could never appear : %@", value);
}];
take:取前兩個
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@"2"];
[subscriber sendNext:@"3"];
[subscriber sendCompleted];
return nil;
}] take:2] subscribeNext:^(id x) {
NSLog(@"only 1 and 2 will be print: %@", x);
}];
skip:跳過第一個
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@"2"];
[subscriber sendNext:@"3"];
[subscriber sendCompleted];
return nil;
}] skip:1] subscribeNext:^(id x) {
NSLog(@"only 2 and 3 will be print: %@", x);
}];
throttle:節流
可能大家還是不理解,我給大家舉個例子吧,我們公司曾經有一個需求,當用戶再輸入框輸入的文本發生改變的時候可以請求數據,做到及時搜索的功能。就像百度現在的搜索體驗。做到這個如果不考慮服務器壓力其實沒那么難,但是我們是追求完美的人,怎么能不考慮服務器性能呢。那么就有一個問題,一旦輸入框發生改變我們就要從服務器獲取數據嗎,當然不能這樣,這里我們如果有一個時間延遲那就最好了,那就是節流。
這里再介紹一下switchToLatest,當我們搜索的時候下一個搜索已經開始了可能上一個搜索還沒返回結果,我們就沒必要開啟上一個搜索了,肯定是去最新的吧。所以switchToLatest就是這樣的一個功能。好了,下面就是兩者結合給我們的搜索優化的一段代碼
[[[[[[textField.rac_textSignal throttle:0.3]distinctUntilChanged]ignore:@""] map:^id(id value) {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// network request
[subscriber sendNext:value];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
// cancel request
}];
}];
}]switchToLatest] subscribeNext:^(id x) {
NSLog(@"x = %@",x);
}];
repeat:重復
[[[[[RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"rac"];
[subscriber sendCompleted];
return nil;
}]delay:1]repeat]take:10] subscribeNext:^(id x) {
NSLog(@"x = %@",x);
} completed:^{
NSLog(@"完成");
}];
merge:合并 同時訂閱,各自執行
RACSignal * signalA = [RACSignal createSignal:^RACDisposable *(id subscriber) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"A");
[subscriber sendNext:@"a"];
[subscriber sendCompleted];
});
return nil;
}];
RACSignal * signalB = [RACSignal createSignal:^RACDisposable *(id subscriber) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"B");
[subscriber sendNext:@"b"];
[subscriber sendCompleted];
});
return nil;
}];
[[RACSignal merge:@[signalA, signalB]]subscribeNext:^(id x) {
NSLog(@"x = %@",x);
}];
concat: 一個異步請求完成后,再啟動另一個
RACSignal * signalA = [RACSignal createSignal:^RACDisposable *(id subscriber) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"a");
[subscriber sendNext:@"a"];
[subscriber sendCompleted];
});
return nil;
}];
RACSignal * signalB = [RACSignal createSignal:^RACDisposable *(id subscriber) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"b");
[subscriber sendNext:@"b"];
[subscriber sendCompleted];
});
return nil;
}];
[[signalA concat:signalB]subscribeNext:^(id x) {
NSLog(@"x=%@",x);
}];
zipWith:/combineLatest: 多個異步請求都完成后,再做某件事
RACSignal * signalA = [RACSignal createSignal:^RACDisposable *(id subscriber) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"a");
[subscriber sendNext:@"a"];
[subscriber sendCompleted];
});
return nil;
}];
RACSignal * signalB = [RACSignal createSignal:^RACDisposable *(id subscriber) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"b");
[subscriber sendNext:@"b"];
[subscriber sendCompleted];
});
return nil;
}];
[[signalA zipWith:signalB]subscribeNext:^(id x) {
NSLog(@"x = %@",x);
}];
RAC的一些宏
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
[self.view addSubview:button];
button.frame = CGRectMake(100, 100, 180, 40);
RAC(button, backgroundColor) = [RACObserve(button, selected) map:^UIColor *(NSNumber * selected) {
return [selected boolValue] ? [UIColor redColor] : [UIColor greenColor];
}];
[[button rac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(UIButton * btn) {
btn.selected = !btn.selected;
}];
RAC(showLabel, text) = mytextField.rac_textSignal;
RAC(showLabel, text) = [[[mytextField.rac_textSignal
startWith:@"不足3個字"] // startWith 一開始返回的初始值
filter:^BOOL(NSString *value) { // filter使滿足條件的值才能傳出
return value.length > 3;
}]map:^id(id value) {
// map將一個值轉化為另一個值輸出
return [value isEqualToString:@"meiqing"] ? @"驗證成功!" : value;
}];
如果覺得文章還不錯,可以打賞哦。
微博賬號:梅嘉慶(點擊關注)