RAC(Reactive Cocoa)常見的類

一個蘿蔔壹個坑發表於2017-12-22

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];

相關文章