上篇寫的ReactiveCocoa-上手其實很簡單(一),相信大家已經對RAC有了 感悟,對其簡單的運用應該也是沒什么問題的,如果有些模糊我們可以回顧下上一篇文章講解,俗話說:溫故而知新、書讀百遍,其義自見嘛。
今天我們來進一步了解RAC的核心類及RAC的進階使用。
關于RACSubject
RACSubject:信號提供者,非常特殊,自己可以充當信號,又能發送信號。
場景:一般在傳值、回調的時候、替代delegate的時候使用。
下面來看個例子:當前控制器點擊按鈕,push到另一個控制器界面,另一個控制器點擊按鈕,返回控制器的第一個頁面和接收到第二個界面的消息。
OneViewController
- (void)viewDidLoad {
[super viewDidLoad];
/*
// RACSubject使用步驟
// 1.創建信號 [RACSubject subject],創建信號時沒有block。
// 2.訂閱信號 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// 3.發送信號 sendNext:(id)value
// RACSubject:底層實現和RACSignal不一樣。
// 1.調用subscribeNext訂閱信號,只是把訂閱者保存起來,并且訂閱者的nextBlock已經賦值了。
// 2.調用sendNext發送信號,遍歷剛剛保存的所有訂閱者,一個一個調用訂閱者的nextBlock。
*/
self.button.frame = CGRectMake(100, 100, 80, 30);
[self.view addSubview:self.button];
}
#pragma mark---lazy loading
- (UIButton *)button {
if (!_button) {
_button = [[UIButton alloc] init];
[_button setBackgroundColor:[UIColor redColor]];
[_button setTitle:@"Go To" forState:UIControlStateNormal];
//使用rac_signalForControlEvents,處理button點擊事件
[[_button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
TwoViewController *twoVC = [[TwoViewController alloc] init];
//1.創建信號 [RACSubject subject]
twoVC.subject = [RACSubject subject];
//2.調用sendNext發送信號
[twoVC.subject subscribeNext:^(id x) { // 這里的x便是sendNext發送過來的信號
NSLog(@"%@", x);
[self.button setTitle:x forState:UIControlStateNormal];
}];
[self.navigationController pushViewController:twoVC animated:YES];
}];
}
return _button;
}
TwoViewController
@property (nonatomic,strong) RACSubject *subject;
- (void)viewDidLoad {
[super viewDidLoad];
self.button.frame = CGRectMake(50, 100, 50, 30);
self.view.backgroundColor = [UIColor purpleColor];
[self.view addSubview:self.button];
}
#pragma mark---lazy loading
- (UIButton *)button {
if (!_button) {
_button = [[UIButton alloc] init];
[_button setBackgroundColor:[UIColor grayColor]];
[_button setTitle:@"Two Go" forState:UIControlStateNormal];
[[_button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
//3.發送信號,傳遞的值,替代delegate
[self.subject sendNext:@"zm"];
[self.navigationController popViewControllerAnimated:YES];
}];
}
return _button;
}
RACSubject和RACReplaySubject的區別:
RACSubject必須要先訂閱信號之后才能發送信號,而RACReplaySubject可以先發送信號后訂閱,重復提供信號類。
使用場景一:如果一個信號每被訂閱一次,就需要把之前的值重復發送一遍,使用重復提供信號類。
使用場景二:可以設置capacity數量來限制緩存的value的數量,即只緩充最新的幾個值。
關于RACCommand
RACCommand:RAC中用于處理事件的類,可以把事件如何處理,事件中的數據如何傳遞,包裝到這個類中,他可以很方便的監控事件的執行過程。
場景:監聽按鈕點擊,網絡請求
注意事項:
1.signalBlock不能返回nil,必須返回一個信號或者[RACSignal empty]
2.RACCommand中信號如果數據傳遞完,必須調用[subscriber sendCompleted],代表執行完畢,否則永遠處于執行中。
3.特別注意RACCommand需要被強引用,否則接收不到RACCommand中的信號,RACCommand中的信號是延遲發送的。
獲取RACCommand返回的信號源數據執行方法:
1.執行信號源executionSignals,這個是signal of signals(信號的信號),意思是信號發出的數據是信號,不是普通的類型。
2.訂閱executionSignals就能拿到RACCommand中返回的信號,然后訂閱signalBlock返回的信號,就能獲取發出的值。
3.監聽當前命令是否正在執行executing
具體實現例子:
- (void)test1 {
// RACCommand: 處理事件
//1.創建
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
//block調用,execute執行命令的時候就會調用
// input 為執行命令傳進來的參數
// 不能返回空的信號 這里的返回值不允許為nil
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"執行命令產生的數據"];
return nil;
}];
}];
// 訂閱命令內部的信號
// ** 方式一:直接訂閱執行命令返回的信號
//2.執行命令
RACSignal *signal =[command execute:@1]; // 這里其實用到的是replaySubject 可以先發送命令再訂閱
// 在這里就可以訂閱信號了
[signal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
//**方法二:
// 訂閱signal of signals(信號的信號)
// 注意:這里必須是先訂閱才能發送命令
// executionSignals:信號源,信號中信號,signalofsignals:信號,發送數據就是信號
[command.executionSignals subscribeNext:^(RACSignal *x) {
[x subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// NSLog(@"%@", x);
}];
// 2.執行命令
[command execute:@2];
// **方式三
// switchToLatest獲取最新發送的信號,只能用于信號中信號。
[command.executionSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 2.執行命令
[command execute:@3];
}
/*
RACCommand 通常用來表示某個Action的執行,比如點擊Button。它有幾個比較重要的屬性:executionSignals / errors / executing。
1、executionSignals是signal of signals,如果直接subscribe的話會得到一個signal,而不是我們想要的value,所以一般會配合switchToLatest。
2、errors。跟正常的signal不一樣,RACCommand的錯誤不是通過sendError來實現的,而是通過errors屬性傳遞出來的。
3、executing表示該command當前是否正在執行。
*/
// 監聽事件有沒有完成
- (void)test2 {
//注意:當前命令內部發送數據完成,一定要主動發送完成
// 1.創建命令
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
// block調用:執行命令的時候就會調用
// 這里的返回值不允許為nil
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 發送數據
[subscriber sendNext:@"執行命令產生的數據"];
// *** 發送完成 **
[subscriber sendCompleted];
return nil;
}];
}];
// 監聽事件有沒有完成
[command.executing subscribeNext:^(id x) {
if ([x boolValue] == YES) { // 正在執行
NSLog(@"當前正在執行%@", x);
}else {
// 執行完成/沒有執行
NSLog(@"執行完成/沒有執行");
}
}];
// 2.執行命令
[command execute:@1];
}
關于RACMulticastConnection
RACMulticastConnection:用于當一個信號,被多次訂閱時,為了保證創建信號時,避免多次調用創建信號中的block,造成副作用,可以使用這個類處理。
注意事項:RACMulticastConnection通過RACSignal的-publish或者-muticast:方法創建.
使用場景:解決多次調用問題--假設在一個信號中發送請求,每次訂閱一次都會發送請求,這樣就會導致多次請求。
使用步驟:
1.創建信號 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
2.創建連接 RACMulticastConnection *connect = [signal publish];
3.訂閱信號,注意:訂閱的不在是之前的信號,而是連接的信號。 [connect.signal subscribeNext:nextBlock]
4.連接 [connect connect]
具體實現例子:
- (void)test {
// 使用RACMulticastConnection,無論有多少個訂閱者,無論訂閱多少次,只發送一個。
// 1.發送請求,用一個信號內包裝,不管有多少個訂閱者,只想發一次請求
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 發送請求
NSLog(@"發送請求啦");
// 發送信號
[subscriber sendNext:@"data"];
return nil;
}];
//2. 創建連接類
RACMulticastConnection *connection = [signal publish];
[connection.signal subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
[connection.signal subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
[connection.signal subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
//3. 連接。只有連接了才會把信號源變為熱信號
[connection connect];
}
今天就寫到這里,這篇主要寫了下一些常用的使用類及常用的使用場景,下篇準備寫下操作符的使用。大家有什么疑惑的可以留言。