ReactiveCocoa常見的類
RACSignal:訊號類;RACSubscriber是協議
簡介
有資料產生時就會使用RACSignal類
預設是冷訊號,必須訂閱訊號類
RACSignal使用步驟
建立訊號(預設建立的是冷訊號)
didSubscribe呼叫:只要一個訊號被訂閱就會呼叫
didSubscribe作用:傳送資料
訂閱訊號(變為熱訊號)subscribeNext:訂閱
nextBlock呼叫:只要訂閱者傳送資料就會呼叫
nextBlock作用:處理資料,展示在UI上面
傳送訊號(sendNext:)
只要訂閱者呼叫sendNext就會執行nextBlock
只要訂閱RACDynamicSignal就會執行didSubscribe
前提條件是RACDynamicSignal,不同型別訊號的訂閱,處理訂閱的事情不一樣
RACSignal使用步驟:
1.建立訊號 + (RACSignal *)createSignal:(RACDisposable * (^)(id 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 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. RACDisposable:取消訂閱
只要訊號傳送資料完畢就會自動取消訂閱
只要訂閱者在就不會自動取消訊號的訂閱
呼叫[disposable dispose];就會取消
3. RACSubject:訊號提供者,自己可以充當訊號,也可以充當訂閱者
必須先訂閱再傳送訊號
使用場景: 通常用來代替代理,有了他就不必定義代理了
RACSubject使用步驟
1.建立訊號 [RACSubject subject],跟RACSiganl不一樣,建立訊號時沒有block。
2.訂閱訊號 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
3.傳送訊號 sendNext:(id)value
RACSubject:底層實現和RACSignal不一樣。
1.呼叫subscribeNext訂閱訊號,只是把訂閱者儲存起來,並且訂閱者的nextBlock已經賦值了。
2.呼叫sendNext傳送訊號,遍歷剛剛儲存的所有訂閱者,一個一個呼叫訂閱者的nextBlock。
// 1.建立訊號
RACSubject *subject = [RACSubject subject];
// 2.訂閱訊號
[subject subscribeNext:^(id x) {
// block呼叫時刻:當訊號發出新值,就會呼叫.
NSLog(@"第一個訂閱者%@",x);
}];
[subject subscribeNext:^(id x) {
// block呼叫時刻:當訊號發出新值,就會呼叫.
NSLog(@"第二個訂閱者%@",x);
}];
// 3.傳送訊號
[subject sendNext:@"1"];
4. RACReplaySubject: 重複提供訊號類,是RACSubject的子類
RACReplaySubject可以先傳送訊號,在訂閱訊號,RACSubject就不可以。
使用場景一`:如果一個訊號每被訂閱一次,就需要把之前的值重複傳送一遍,使用重複提供訊號類。
使用場景二`:可以設定capacity數量來限制快取的value的數量,即只緩充最新的幾個值。
RACReplaySubject使用步驟:
1.建立訊號 [RACSubject subject],跟RACSiganl不一樣,建立訊號時沒有block。
2.可以先訂閱訊號,也可以先傳送訊號。
2.1 訂閱訊號 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
2.2 傳送訊號 sendNext:(id)value
RACReplaySubject:底層實現和RACSubject不一樣。
1.呼叫sendNext傳送訊號,把值儲存起來,然後遍歷剛剛儲存的所有訂閱者,一個一個呼叫訂閱者的nextBlock。
2.呼叫subscribeNext訂閱訊號,遍歷儲存的所有值,一個一個呼叫訂閱者的nextBlock
如果想當一個訊號被訂閱,就重複播放之前所有值,需要先傳送訊號,在訂閱訊號。也就是先儲存值,在訂閱值。
// 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);
}];
>>> RACSubject替換代理
需求:
1.給當前控制器新增一個按鈕,modal到另一個控制器介面
2.另一個控制器view中有個按鈕,點選按鈕,通知當前控制器
步驟一:在第二個控制器.h,新增一個RACSubject代替代理。
@interface TwoViewController : UIViewController
@property (nonatomic, strong) RACSubject *delegateSignal;
@end
步驟二:監聽第二個控制器按鈕點選
@implementation TwoViewController
- (IBAction)notice:(id)sender {
// 通知第一個控制器,告訴它,按鈕被點了
// 通知代理
// 判斷代理訊號是否有值
if (self.delegateSignal) {
// 有值,才需要通知
[self.delegateSignal sendNext:nil];
}
}
@end
步驟三:在第一個控制器中,監聽跳轉按鈕,給第二個控制器的代理訊號賦值,並且監聽.
@implementation OneViewController
- (IBAction)btnClick:(id)sender {
// 建立第二個控制器
TwoViewController *twoVc = [[TwoViewController alloc] init];
// 設定代理訊號
twoVc.delegateSignal = [RACSubject subject];
// 訂閱代理訊號
[twoVc.delegateSignal subscribeNext:^(id x) {
NSLog(@"點選了通知按鈕");
}];
// 跳轉到第二個控制器
[self presentViewController:twoVc animated:YES completion:nil];
}
@end
5. RACTuple: 元組類
RACSequence:集合類,用於代替NSArray,NSDictionary,可以用來快速遍歷陣列和字典
// 1.遍歷陣列
NSArray *numbers = @[@1,@2,@3,@4];
// 這裡其實是三步
// 第一步: 把陣列轉換成集合RACSequence numbers.rac_sequence
// 第二步: 把集合RACSequence轉換RACSignal訊號類,numbers.rac_sequence.signal
// 第三步: 訂閱訊號,啟用訊號,會自動把集合中的所有值,遍歷出來。
[numbers.rac_sequence.signal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 2.遍歷字典,遍歷出來的鍵值對會包裝成RACTuple(元組物件)
NSDictionary *dict = @{@"name":@"HMJ",@"age":@18};
[dict.rac_sequence.signal subscribeNext:^(RACTuple *x) {
// 解包元組,會把元組的值,按順序給引數裡面的變數賦值
RACTupleUnpack(NSString *key, NSString *value) = x;
// 相當於以下寫法
// NSString *key = x[0];
// NSString *value = x[1];
NSLog(@"%@ %@",key,value);
}];
3.字典轉模型
3.1 OC寫法
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil];
NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath];
NSMutableArray *items = [NSMutableArray array];
for (NSDictionary *dict in dictArr) {
FlagItem *item = [FlagItem flagWithDict:dict];
[items addObject:item];
}
3.2 RAC寫法
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil];
NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath];
NSMutableArray *flags = [NSMutableArray array];
_flags = flags;
// rac_sequence注意點:呼叫subscribeNext,並不會馬上執行nextBlock,而是會等一會。
[dictArr.rac_sequence.signal subscribeNext:^(id x) {
// 運用RAC遍歷字典,x:字典
FlagItem *item = [FlagItem flagWithDict:x];
[flags addObject:item];
}];
NSLog(@"%@", NSStringFromCGRect([UIScreen mainScreen].bounds));
3.3 RAC高階寫法:
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil];
NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath];
// map:對映的意思,目的:把原始值value對映成一個新值
// array: 把集合轉換成陣列
// 底層實現:當訊號被訂閱,會遍歷集合中的原始值,對映成新值,並且儲存到新的陣列裡。
NSArray *flags = [[dictArr.rac_sequence map:^id(id value) {
return [FlagItem flagWithDict:value];
}] array];