通過Cocoapods集成pod ‘ReactiveObjC’
然後在項目中導入 #import <ReactiveObjC/ReactiveObjC.h>
創建RACSignal 對象,並且發送消息
@weakify(self)
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
@strongify(self)
self.data = [[Model alloc] init];
self.data.nameStr = @"測試完成";
[subscriber sendNext:self.data];
[subscriber sendCompleted];
return nil;
}];
[signal subscribeNext:^(id _Nullable x)
{
NSLog(@"x==========%@\n",x);
}];
下面是另外一種寫法
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"1"];
return [RACDisposable disposableWithBlock:^{
}];;
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"結果是========%@",x);
}];
將上面的RAC轉換成flatten
RACSignal *flattenMapSignal = [signal flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
return RACObserve(self.data, nameStr);
}];
[flattenMapSignal subscribeNext:^(id _Nullable x) {
NSLog(@"結果是=========%@\n",x);
}];
創建RACSubject對象,執行完之後,就會執行rac_willDeallocSignal 方法
RACSubject *subject = [RACSubject subject];
[subject.rac_willDeallocSignal subscribeCompleted:^{
}];
[subject subscribeNext:^(id x) { //3
NSLog(@"next = %@", x);
}];
[subject sendNext:@1];
UITextField綁定textSignal 輸出結果
[[_textField.rac_textSignal bind:^RACSignalBindBlock _Nullable{
return ^RACSignal *(id value,BOOL *stop){
return [RACReturnSignal return:[NSString stringWithFormat:@"輸出:%@",value]];
};
}]subscribeNext:^(id _Nullable x) {
NSLog(@"結果是=====%@\n",x);
}] ;
RACReplaySubject 傳的信號會重複播放
// 1.創建信號
//1.創建信號
RACReplaySubject *replaySubject = [RACReplaySubject subject];
//2.發送信號
[replaySubject sendNext:@1];
[replaySubject sendNext:@2];
//3.訂閱信號
[replaySubject subscribeNext:^(id x) {
NSLog(@"第一個訂閱者接收到的數據%@",x);
}];
//訂閱信號
[replaySubject subscribeNext:^(id x) {
NSLog(@"第二個訂閱者接收到的數據%@",x);
}];
retry 當信號出錯的時候 重新執行信號操作
__block int i = 0;
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
if(i==10)
{
[subscriber sendNext:@1];
}else{
NSLog(@"接收到錯誤");
[subscriber sendError:nil];
}
i++;
return nil;
}] retry] subscribeNext:^(id x) {
NSLog(@"retry%@",x);
} error:^(NSError *error) {
}];
delay 延遲2s執行
RACSignal *signal = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
return nil;
}] delay:2] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
RACScheduler 定時做任務,當離開當前頁面取消任務
self.disposable = [[[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(NSDate * _Nullable x) {
NSLog(@"做完這件事");
[self.disposable dispose];
}];
timeout 可以讓信號在一定的時間後,自動報錯
RACSignal *signal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
return nil;
}]timeout:1 onScheduler:[RACScheduler currentScheduler]];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"====%@\n",x);
} error:^(NSError * _Nullable error) {
//1秒後會自動調用
NSLog(@"%@",error);
}];
觀察某個對象的某個值的變化,並進行過濾
[[RACObserve(self,self.data) filter:^BOOL(id _Nullable value) {
return value;
}] subscribeNext:^(Model *x) {
NSLog(@"執行了這裏=======%@\n",x.nameStr);
}];
NSNotificationCenter 之觀察
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"postData" object:nil] subscribeNext:^(NSNotification * _Nullable x) {
NSLog(@"結果是-------%@\n",x.userInfo);
}];
監聽按鈕的事件
UIButton *button =[[UIButton alloc]initWithFrame:CGRectMake(50, 100, 30, 30)];
button.backgroundColor =[UIColor redColor];
[self.view addSubview:button];
[[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
}];
flattenMap 將信號包裝一層發送出去
[[self.phoneTextView.rac_textSignal flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) {
return [RACReturnSignal return:[NSString stringWithFormat:@"輸出:%@",value]];
}]subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
concat:按一定順序拼接信號,當多個信號發出的時候,有順序的接收信號,把signalA拼接到signalB後,signalA發送完成,signalB纔會被激活。訂閱拼接的信號,不需要單獨訂閱signalA,signalB
注意:第一個信號必鬚髮送完成,第二個信號纔會被激活
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@2];
return nil;
}];
RACSignal *concatSignal = [signalA concat:signalB];
[concatSignal subscribeNext:^(id x) {
NSLog(@"kl==========%@",x);
}];
then:用於連接兩個信號,當第一個信號完成,纔會連接then返回的信號
then:用於連接兩個信號,當第一個信號完成,纔會連接then返回的信號
注意使用then,之前信號的值會被忽略掉.
底層實現:1、先過濾掉之前的信號發出的值。2.使用concat連接then返回的信號
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}] then:^RACSignal *{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@12];
return nil;
}];
}] subscribeNext:^(id x) {
// 只能接收到第二個信號的值,也就是then返回信號的值
NSLog(@"then================%@",x);
}];
merge
:把多個信號合併爲一個信號,任何一個信號有新值的時候就會調用,merge:把多個信號合併成一個信號,創建多個信號
底層實現:
// 1.合併信號被訂閱的時候,就會遍歷所有信號,並且發出這些信號。
// 2.每發出一個信號,這個信號就會被訂閱
// 3.也就是合併信號一被訂閱,就會訂閱裏面所有的信號。
// 4.只要有一個信號被髮出就會被監聽。
//`merge`:把多個信號合併爲一個信號,任何一個信號有新值的時候就會調用
//merge:把多個信號合併成一個信號
//創建多個信號
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@2];
return nil;
}];
//合併信號,任何一個信號發送數據,都能監聽到.
RACSignal *mergeSignal = [signalA merge:signalB];
[mergeSignal subscribeNext:^(id x) {
NSLog(@"merge==========%@\n",x);
}];
zipWith 把兩個信號壓縮成一個信號,只有當兩個信號同時發出信號內容時,並且把兩個信號的內容合併成一個元祖,纔會觸發壓縮流的next事件
底層實現:
// 1.定義壓縮信號,內部就會自動訂閱signalA,signalB
// 2.每當signalA或者signalB發出信號,就會判斷signalA,signalB有沒有發出個信號,有就會把最近發出的信號都包裝成元組發出。
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@2];
return nil;
}];
//壓縮信號A,信號B
RACSignal *zipSignal = [signalA zipWith:signalB];
[zipSignal subscribeNext:^(RACTwoTuple *x)
{
NSLog(@"zipWith============%@,%@\n\n",x.first,x.second);
}];
combineLatest 將多個信號合併起來,並且拿到各個信號的最新的值,
// 底層實現:
// 1.當組合信號被訂閱,內部會自動訂閱signalA,signalB,必須兩個信號都發出內容,纔會被觸發。
// 2.並且把兩個信號組合成元組發出。
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@5];
return nil;
}];
// 把兩個信號組合成一個信號,跟zip一樣,沒什麼區別
RACSignal *combineSignal = [signalA combineLatestWith:signalB];
[combineSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
reduce
聚合:用於信號發出的內容是元組,把信號發出元組的值聚合成一個值,聚合
常見的用法,(先組合在聚合)。combineLatest:(id)signals reduce:(id (^)())reduceBlock
// reduce中的block簡介:
// reduceblcok中的參數,有多少信號組合,reduceblcok就有多少參數,每個參數就是之前信號發出的內容
// reduceblcok的返回值:聚合信號之後的內容。
底層實現:訂閱聚合信號,每次有內容發出,就會執行reduceblcok,把信號內容轉換成reduceblcok返回的值
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber)
{
[subscriber sendNext:@8];
return nil;
}];
RACSignal *reduceSignal = [RACSignal combineLatest:@[signalA,signalB] reduce:^id(NSNumber *num1 ,NSNumber *num2){
return [NSString stringWithFormat:@"%@ %@",num1,num2];
}];
[reduceSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
filter:過濾信號,使用它可以獲取滿足條件的信號. 每次信號發出,會先執行過濾條件判斷
[_textField.rac_textSignal filter:^BOOL(NSString *value) {
return value.length > 3;
}];
ignore:忽略完某些值的信號.
[[_phoneTextView.rac_textSignal ignore:@"1"] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
distinctUntilChanged:當上一次的值和當前的值有明顯的變化就會發出信號,否則會被忽略掉。
// 過濾,當上一次和當前的值不一樣,就會發出內容。
// 在開發中,刷新UI經常使用,只有兩次數據不一樣才需要刷新
[[_phoneTextView.rac_textSignal distinctUntilChanged] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
take:從開始一共取N次的信號 1、創建信號
// RACSubject *signal = [RACSubject subject];
//
// // 2、處理信號,訂閱信號
// [[signal take:3] subscribeNext:^(id x) {
//
// NSLog(@"%@",x);
// }];
//
// // 3.發送信號
// [signal sendNext:@1];
//
// [signal sendNext:@6];
// [signal sendNext:@61];
// takeLast:取最後N次的信號,前提條件,訂閱者必須調用完成,因爲只有完成,就知道總共有多少信號.
// 1、創建信號
// RACSubject *signal = [RACSubject subject];
//
// // 2、處理信號,訂閱信號
// [[signal takeLast:1] subscribeNext:^(id x) {
//
// NSLog(@"%@",x);
// }];
//
// // 3.發送信號
// [signal sendNext:@1];
//
// [signal sendNext:@2];
//[signal sendNext:@232];
// [signal sendCompleted];
// takeUntil:(RACSignal *):獲取信號直到某個信號執行完成
takeUntil 噹噹前對象被銷燬時,停止執行
[_textField.rac_textSignal takeUntil:self.rac_willDeallocSignal];
skip:(NSUInteger):跳過幾個信號,不接受
[_phoneTextView.rac_textSignal skip:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
switchToLatest 用於signalOfSignals(信號的信號),有時候信號也會發出信號,會在signalOfSignals中,獲取signalOfSignals發送的最新信號。
RACSubject *signalOfSignals = [RACSubject subject];
RACSubject *signal = [RACSubject subject];
// 獲取信號中信號最近發出信號,訂閱最近發出的信號。
// 注意switchToLatest:只能用於信號中的信號
[signalOfSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[signalOfSignals sendNext:signal];
[signal sendNext:@1];
ReactiveCocoa操作方法之秩序。
doNext: 執行Next之前,會先執行這個Block
doCompleted: 執行sendCompleted之前,會先執行這個Block
[[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}] doNext:^(id x) {
// 執行[subscriber sendNext:@1];之前會調用這個Block
NSLog(@"doNext");;
}] doCompleted:^{
// 執行[subscriber sendCompleted];之前會調用這個Block
NSLog(@"doCompleted");;
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
ReactiveCocoa操作方法之線程
deliverOn: 內容傳遞切換到制定線程中,副作用在原來線程中,把在創建信號時block中的代碼稱之爲副作用
subscribeOn: 內容傳遞和副作用都會切換到制定線程中。
數組操作
Array *numbers = @[@1,@2,@3,@4];
[numbers.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"數據=======%@\n",x);
}];
字典操作
NSDictionary *dict = @{@"name":@"xmg",@"age":@10};
[dict.rac_sequence.signal subscribeNext:^(RACTuple *x) {
RACTupleUnpack(NSString *key,NSString *value) = x;
NSLog(@"===%@",key);
NSLog(@"=====%@",value);
}];
map 映射成新的數據
NSArray *numbers = @[@1,@2,@3,@4];
NSArray *numbers2 = [[numbers.rac_sequence map:^id _Nullable(id _Nullable value) {
return value;
}]array] ;
RACCommand 命令執行
mand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"請求數據"];
[subscriber sendCompleted];
return nil;
}];
}];
self.command = command;
// self.btnClick.rac_command = command;
// [self.btnClick.rac_command.executionSignals subscribeNext:^(RACSignal<id> * _Nullable x) {
//
// NSLog(@"===%@\n",x);
//
// [x subscribeNext:^(id _Nullable x) {
//
// NSLog(@"2222===%@\n",x);
//
// }];
// }];
[self.command.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) {
NSLog(@"4444===%@\n",x);
}];
[[command.executing skip:1] subscribeNext:^(id x) {
//
// if ([x boolValue] == YES) {
// // 正在執行
// NSLog(@"正在執行");
//
// }else{
// // 執行完成
// NSLog(@"執行完成");
// }
//
// }];
[self.command execute:@1];
1.代替代理
// 需求:自定義redView,監聽紅色view中按鈕點擊
// 之前都是需要通過代理監聽,給紅色View添加一個代理屬性,點擊按鈕的時候,通知代理做事情
// rac_signalForSelector:把調用某個對象的方法的信息轉換成信號,就要調用這個方法,就會發送信號。
// 這裏表示只要redV調用btnClick:,就會發出信號,訂閱就好了。
[[redV rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
// NSLog(@"點擊紅色按鈕");
// }];
// 2.KVO
// // 把監聽redV的center屬性改變轉換成信號,只要值改變就會發送信號
// // observer:可以傳入nil
// [[redV rac_valuesAndChangesForKeyPath:@"center" options:NSKeyValueObservingOptionNew observer:nil] subscribeNext:^(id x) {
//
// NSLog(@"%@",x);
//
// }];
// // 把按鈕點擊事件轉換爲信號,點擊按鈕,就會發送信號
// [[self.btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
//
// NSLog(@"按鈕被點擊了");
// }];
//
// // 4.代替通知
// // 把監聽到的通知轉換信號
// [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
// NSLog(@"鍵盤彈出");
// }];
// // 6.處理多個請求,都返回結果的時候,統一做處理.
// RACSignal *request1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//
// // 發送請求1
// [subscriber sendNext:@"發送請求1"];
// return nil;
// }];
//
// RACSignal *request2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// // 發送請求2
// [subscriber sendNext:@"發送請求2"];
// return nil;
// }];
//
// // 使用注意:幾個信號,參數一的方法就幾個參數,每個參數對應信號發出的數據。
// [self rac_liftSelector:@selector(updateUIWithR1:r2:) withSignalsFromArray:@[request1,request2]];
屬性綁定
RAC(self.labelView,text) = _textField.rac_textSignal;
[RACObserve(self.view, center) subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
將數據包裝成元祖
RACTuple *tuple = RACTuplePack(@10,@20);
TupleUnpack(NSString *number) = tuple;
[[[tuple.rac_sequence map:^id _Nullable(id _Nullable value) {
return value;
}]signal]subscribeNext:^(id _Nullable x) {
NSLog(@"number============%@\n",x);
}];
throttle 節流,當某個信號發送比較頻繁的時候,可以使用節流
// 節流:當某個信號發送比較頻繁時,可以使用節流,在某一段時間不發送信號內容,過了一段時間獲取信號的最新內容發出。
// RACSubject *subject = [RACSubject subject];
// // 節流1秒,1秒後接收最後一個發送的信號
// [[subject throttle:1] subscribeNext:^(id x) {
// NSLog(@"%@", x);
// }];
// [subject sendNext:@1];
// [subject sendNext:@2];
// [subject sendNext:@3];