你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS-ReactiveCocoa

iOS-ReactiveCocoa

編輯:IOS開發綜合

以作用為導向去學習一類新技能,首先了解這個是用來做什麼的?

首先ReactiveCocoa在github上的截圖

這裡寫圖片描述

它的星星相當多,然後它的維護也很勤,更新頻率挺高

ReactiveCocoa開發中常見用法。

在我們iOS開發過程中,當某些事件響應的時候,需要處理某些業務邏輯,這些事件都用不同的方式來處理。
比如按鈕的點擊使用action,ScrollView滾動使用delegate,屬性值改變使用KVO等系統提供的方式。
其實這些事件,都可以通過RAC處理
ReactiveCocoa為事件提供了很多處理方法,而且利用RAC處理事件很方便,可以把要處理的事情,和監聽的事情的代碼放在一起,這樣非常方便我們管理,就不需要跳到對應的方法裡。非常符合我們開發中高聚合,低耦合的思想

1 代替代理:

rac_signalForSelector:用於替代代理。

2 代替KVO :

rac_valuesAndChangesForKeyPath:用於監聽某個對象的屬性改變。

3 監聽事件:

rac_signalForControlEvents:用於監聽某個事件。

4 代替通知:

rac_addObserverForName:用於監聽某個通知。

5 監聽文本框文字改變:

rac_textSignal:只要文本框發出改變就會發出這個信號。

6 處理當界面有多次請求時,需要都獲取到數據時,才能展示界面

rac_liftSelector:withSignalsFromArray:Signals:當傳入的Signals(信號數組),每一個signal都至少sendNext過一次,就會去觸發第一個selector參數的方法。 使用注意:幾個信號,參數一的方法就幾個參數,每個參數對應信號發出的數據。

ReactiveCocoa常見類。

學習框架首要之處:個人認為先要搞清楚框架中常用的類,在RAC中最核心的類RACSiganl,搞定這個類就能用ReactiveCocoa開發了。

RACSiganl:信號類,一般表示將來有數據傳遞,只要有數據改變,信號內部接收到數據,就會馬上發出數據。

信號類(RACSiganl),只是表示當數據改變時,信號內部會發出數據,它本身不具備發送信號的能力,而是交給內部一個訂閱者去發出。

默認一個信號都是冷信號,也就是值改變了,也不會觸發,只有訂閱了這個信號,這個信號才會變為熱信號,值改變了才會觸發。

如何訂閱信號:調用信號RACSignal的subscribeNext就能訂閱。

// RACSignal:有數據產生的時候,就使用RACSignal
// RACSignal使用步驟: 1.創建信號  2.訂閱信號 3.發送信號
-(void)RACSingal{
    RACDisposable *(^disposable)(id subscriber) = ^RACDisposable *(idsubscriber) {
        //發送數據
        [subscriber sendNext:@110];
        return NULL;
    };

    //1.創建信號(冷信號)
    RACSignal *signal = [RACSignal createSignal:disposable];
//    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
//        NSLog(@"信號被訂閱!");
//        //發送數據
//        [subscriber sendNext:@110];
//        return NULL;
//    }];

    //2.訂閱信號(熱信號)
    [signal subscribeNext:^(id x) {
        // nextBlock調用:只要訂閱者發送數據就會調用
        // nextBlock作用:處理數據,展示到UI上面
        // x:信號發送的內容
        NSLog(@"%@",x);
    }];

    // 只要訂閱者調用sendNext,就會執行nextBlock
    // 只要訂閱RACDynamicSignal,就會執行didSubscribe
    // 前提條件是RACDynamicSignal,不同類型信號的訂閱,處理訂閱的事情不一樣
}

RACSubscriber:表示訂閱者的意思,用於發送信號,這是一個協議,不是一個類,只要遵守這個協議,並且實現方法才能成為訂閱者。通過create創建的信號,都有一個訂閱者,幫助他發送數據。

RACDisposable:用於取消訂閱或者清理資源,當信號發送完成或者發送錯誤的時候,就會自動觸發它。

使用場景:不想監聽某個信號時,可以通過它主動取消訂閱信號。
-(void)RACDisposable{
    //1.創建信號
    RACDisposable *(^disposable)(id subscriber) = ^RACDisposable *(idsubscriber){
        //3.發送信號
        _subscriber = subscriber;
        [subscriber sendNext:@"發送信號123"];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"信號被取消訂閱了!");
        }];
    };
    RACSignal *signal = [RACSignal createSignal:disposable];

    //2.訂閱信號
    RACDisposable *Disposable = [signal subscribeNext:^(id x) {
        NSLog(@"獲取到所訂閱的信號:%@",x);
    }];

    //默認信號發送數據完畢後就會主動取消訂閱,不過如果訂閱者一直存在(成員屬性強引用),就不會自動取消訂閱 除非 手動取消訂閱(dispose)
    [Disposable dispose];
}

RACSubject: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。
-(void)RACSubject{
    //1.創建信號
    RACSubject *subject = [RACSubject subject];
    //2.訂閱信號
    [subject subscribeNext:^(id x) {
        NSLog(@"獲取所訂閱的信號信息:%@",x);
    }];
    //3.發送信號
    [subject sendNext:@"hahaha"];
}
-(void)RACSubject2{
    //1.創建信號
    RACSubject *subject = [RACSubject subject];
    //2.訂閱信號
    [subject subscribeNext:^(id x) {
        // block調用時刻:當信號發出新值,就會調用.
        NSLog(@"第一個訂閱者%@",x);
    }];
    [subject subscribeNext:^(id x) {
        // block調用時刻:當信號發出新值,就會調用.
        NSLog(@"第二個訂閱者%@",x);
    }];
    //3.發送信號
    [subject sendNext:@"發送001"];
}

RACReplaySubject:重復提供信號類,RACSubject的子類。
* 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

    // 如果想當一個信號被訂閱,就重復播放之前所有值,需要先發送信號,在訂閱信號。
    // 也就是先保存值,在訂閱值。
-(void)RACReplaySubject{
    //1.創建信號
    RACReplaySubject *replaySubject = [RACReplaySubject subject];
    //2.RACReplaySubject 可以先發送信號   RACSubject 就不可以!
    [replaySubject sendNext:@"987654321"];
    //3.再訂閱信號
    [replaySubject subscribeNext:^(id x) {
       NSLog(@"獲取所訂閱的信息:%@",x);
    }];
}

RACSubject替換代理

需求:
1.給當前控制器添加一個按鈕,modal到另一個控制器界面
2.另一個控制器view中有個按鈕,點擊按鈕,通知當前控制器

步驟一:在第二個控制器.h,添加一個RACSubject代替代理。

#import "ViewController.h"
#import "GlobalHeader.h"
@interface TwoVC : ViewController
@property (nonatomic, strong) RACSubject *delegateSubject;
@end

步驟二:監聽第二個控制器按鈕點擊

- (IBAction)method:(id)sender {
    NSLog(@"Two操作!!");
     // 通知代理
     // 判斷代理信號是否有值
    if (self.delegateSubject) {
        // 有值,才需要通知
        [self.delegateSubject sendNext:@"點擊XXX操作!"];
    }
}

步驟三:在第一個控制器中,監聽跳轉按鈕,給第二個控制器的代理信號賦值,並且監聽.

- (IBAction)modelTwoVC:(id)sender {
    // 創建第二個控制器
    TwoVC *twoVC = [[TwoVC alloc] init];
    // 設置代理信號
    twoVC.delegateSubject = [RACSubject subject];
    // 訂閱代理信號
    [twoVC.delegateSubject subscribeNext:^(id x) {
        NSLog(@"我要進行  %@  操作!!",x);
    }];
    [self presentViewController:twoVC animated:YES completion:^{
        NSLog(@"1VC->2VC");
    }];
}

RACTuple:元組類,類似NSArray,用來包裝值.

RACSequence:RAC中的集合類,用於代替NSArray,NSDictionary,可以使用它來快速遍歷數組和字典。

*遍歷數組和字典:

-(void)RACSequence{
    //****************遍歷數組*********************
    // 第一步: 把數組轉換成集合RACSequence numbers.rac_sequence
    // 第二步: 把集合RACSequence轉換RACSignal信號類,numbers.rac_sequence.signal
    // 第三步: 訂閱信號,激活信號,會自動把集合中的所有值,遍歷出來。
//     NSArray *numbers = @[@1,@2,@3,@4];
//    [numbers.rac_sequence.signal subscribeNext:^(id x) {
//        NSLog(@"遍歷數組:%@",x);
//    }];

    //*****************遍歷字典*********************
    //遍歷出來的鍵值對會包裝成RACTuple(元組對象)
    NSDictionary *dict = @{@"name":@"qxuewei",
                           @"age":@"25",
                           @"phone":@"1851891455"};
    [dict.rac_sequence.signal subscribeNext:^(RACTuple *x) {

//        NSString *key = x[0];
//        NSString *value = x[1];
//        NSLog(@"遍歷字典:key:%@ <-> value:%@",key,value);

        //等同於

        //可以用 解包元素宏定義
        RACTupleUnpack(NSString *KEY,NSString *VALUE) = x;
        NSLog(@"遍歷字典:key:%@ <-> value:%@",KEY,VALUE);
    }];
}

利用 RACSequence 字典轉模型
說起字典轉模型,腦海中會浮現出多種方式,直接系統的KVO,Runtime 或者第三方框架 MJExtension 或者使用 RACSeqience

KVO字典轉模型核心代碼

+(instancetype)ModelWithDict:(NSDictionary *)dict{
    Model *model = [[Model alloc] init];
    //KVO 字典轉模型
    [model setValuesForKeysWithDictionary:dict];
    return model;
}

使用KVO進行解析

 NSMutableArray *arrM = [NSMutableArray array];
    //1. KVO
    NSArray *localArr = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"flags" ofType:@"plist"]];
    [localArr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSDictionary *dict = obj;
        Model *KVOModel = [Model ModelWithDict:dict];
        [arrM addObject:KVOModel];
    }];
    NSLog(@"解析完的模型數組:%@",arrM);

使用 RACSequence 解析

 //2. RACSequence
    [localArr.rac_sequence.signal subscribeNext:^(NSDictionary *x) {
        Model *model = [Model ModelWithDict:x];
        [arrM addObject:model];
    }];

RACSequence 高級用法

 //3. RACSequence高級用法  會把集合中的所有元素都映射到一個新的對象
    arrM = [NSMutableArray arrayWithArray:[[localArr.rac_sequence map:^id(NSDictionary *value) {
        return [Model ModelWithDict:value];
    }] array]];

小結:RAC的用法
1.代替代理

//1.RAC作用一:代替代理
-(void)RAC_Delegate{
    [[self.grayView rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
        NSLog(@"按鈕被點擊了!");
    }];
}

外加上述方法^

2.代理KVO

//2.RAC作用二:代理KVO
//*首先需要導入頭文件   #import "NSObject+RACKVOWrapper.h"
-(void)RAC_KVO1{
    [self.grayView rac_observeKeyPath:@"frame" options:NSKeyValueObservingOptionNew observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
       //代理系統KVO
        NSLog(@"grayView 的Frame發生了改變! 變為:value:%@",value);
    }];
}

KVO的第二種實現可以不導入頭文件 #import “NSObject+RACKVOWrapper.h”

-(void)RAC_KVO2{
    [[self.grayView rac_valuesForKeyPath:@"frame" observer:nil] subscribeNext:^(id x) {
        NSLog(@"grayView 的frame發生的改變,變成了:%@",x);
    }];
}

兩個方法有區別,1方法在設置監聽以後只在所監聽的值改變時調用,2方法在所有監聽值改變都會調用.

比如同樣在

- (void)viewDidLoad {
    [super viewDidLoad];
    [self RAC_KVO1];
    [self RAC_KVO2];
    [self.grayView setFrame:CGRectZero];
}

這裡寫圖片描述

單獨執行
[self RAC_KVO2];
[self.grayView setFrame:CGRectZero];
這裡寫圖片描述

可以看出不同

3.監聽事件

//3.RAC作用三:監聽事件  直接代替系統監聽方法
-(void)RAC_Event{
    [[_BTN rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
        NSLog(@"按鈕被點擊了!");
    }];
}

4.代替通知

//4.RAC作用四:代替通知
-(void)RAC_Noti{
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidShowNotification object:nil] subscribeNext:^(id x) {
        NSLog(@"監聽鍵盤彈出的通知!");
    }];
}

5.監聽文本框內值的改變

//5.RAC作用五:監聽文本框輸入
-(void)RAC_{
    [_textField.rac_textSignal subscribeNext:^(id x) {
        NSLog(@"當前輸入框值:%@",x);
    }];
}
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved