RactiveCocoa

RAC 指的就是 RactiveCocoa 骂租,基于函數(shù)式響應(yīng)式編程思想的Objective-C實踐,是 Github 的一個開源框架读串,能夠幫我們提供大量方便的事件處理方案聊记,讓我們更簡單粗暴地去處理事件.使用MVVM框架就不得不提RAC.RAC具有高聚合低耦合的思想博投,使用RAC會讓代碼更簡潔里烦,邏輯更清晰际插。
RAC幾乎接管了Apple所有的事件機制,由于RAC將Cocoa中KVO哼审、UIKitEvent谐腰、delegate孕豹、selector等都增加了RAC支持,所以都不用去做很多跨函數(shù)的事怔蚌。

ReactiveCocoa主要包含四個組件:
信號源:RACStream 及其子類巩步;
訂閱者:RACSubscriber 的實現(xiàn)類及其子類;
調(diào)度器:RACScheduler 及其子類桦踊;
清潔工:RACDisposable 及其子類椅野。
而信號源是最核心的部分,其它所有組件都是圍繞它運作的籍胯。
RAC 的核心思想:創(chuàng)建信號 - 訂閱信號 - 發(fā)送信號

1. RACSignal 信號類

表示將來有數(shù)據(jù)傳遞竟闪,有數(shù)據(jù)改變,信號內(nèi)部接收到數(shù)據(jù)杖狼,就會馬上發(fā)出數(shù)據(jù)炼蛤,外部就可以接收到數(shù)據(jù)了。默認信號都是冷信號蝶涩,就是這個值改變了它不會觸發(fā)理朋,只有訂閱(調(diào)用信號RACSignal的subscribeNext訂閱)了這個信號,這個信號才會變?yōu)闊嵝盘?值一改變就觸發(fā))绿聘,才會觸發(fā)嗽上。

/* 創(chuàng)建信號 */
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        //RACSubscriber訂閱者對象,用于發(fā)送信號熄攘,這是一個協(xié)議兽愤,不是一個類,只要遵守這個協(xié)議挪圾,并且實現(xiàn)方法才能成為訂閱者浅萧。通過create創(chuàng)建的信號,都有一個訂閱者哲思,幫助他發(fā)送數(shù)據(jù)洼畅。
        /* 發(fā)送信號 */
        [subscriber sendNext:@"發(fā)送信號"];
        
        return [RACDisposable disposableWithBlock:^{
            // 當(dāng)信號發(fā)送完成或者發(fā)送錯誤,就會自動執(zhí)行這個block,取消訂閱信號棚赔。
            // 執(zhí)行完Block后土思,當(dāng)前信號就不在被訂閱了。
            NSLog(@"dealloc");
        }];
        
        //return nil;
    }];
   //接收信號
    [signal subscribeNext:^(id  _Nullable x) {
        
    }];

也可以使用RACDisposable類直接取消訂閱

/* 訂閱信號 */
    RACDisposable *disposable = [signal subscribeNext:^(id  _Nullable x) {
        //RACDisposable用于取消訂閱或者清理資源忆嗜,當(dāng)信號發(fā)送完成或者發(fā)送錯誤的時候己儒,就會自動觸發(fā)它。 當(dāng)你不想監(jiān)聽某個信號時捆毫,可以通過它主動取消訂閱信號闪湾。
        NSLog(@"信號內(nèi)容:%@", x);
    }];
    
    /* 取消訂閱 */
    [disposable dispose];
2. 定時器timer(在子線程執(zhí)行)
    [[RACSignal interval:1.0 onScheduler:[RACScheduler scheduler]] subscribeNext:^(NSDate * _Nullable x) {
        NSLog(@"當(dāng)前時間:%@", x); // x 是當(dāng)前的系統(tǒng)時間
        //關(guān)閉計時器就是取消訂閱
        //[disposable dispose];
    }];
3. RACSubject 信號提供者

RACSubject自己可以充當(dāng)信號,又能發(fā)送信號绩卤。(和代理的用法類似途样,通常用來代替代理江醇,有了它,就不必定義代理了)

/* 創(chuàng)建信號 */
    RACSubject *subject = [RACSubject subject];
    
    /* 訂閱信號(通常在別的視圖控制器中訂閱何暇,與代理的用法類似) */
    [subject subscribeNext:^(id  _Nullable x) {
        /*
         1創(chuàng)建訂閱者對象
         2將block放到訂閱者對象中
         3將訂閱者對象放到subscribes數(shù)組里面
         */
        NSLog(@"信號內(nèi)容:%@", x);
    }];
    
    /* 發(fā)送信號 */
    /*
     其內(nèi)部的真實操作是遍歷信號對象中的數(shù)組,取出訂閱者,調(diào)用訂閱者中的block執(zhí)行
     */
    [subject sendNext:@"發(fā)送信號"];
4. RACTuple 元祖(和 OC 的數(shù)組其實是一樣的陶夜,其實就是封裝了我們 OC 的數(shù)組)
/* 創(chuàng)建元祖 */
    RACTuple *tuple1 = [RACTuple tupleWithObjects:@"1", @"2", @"3", @"4", @"5", nil];
    
    /* 從別的數(shù)組中獲取內(nèi)容 */
    RACTuple *tuple2 = [RACTuple tupleWithObjectsFromArray:@[@"1", @"2", @"3", @"4", @"5"]];
    
    /* 利用 RAC 宏快速封裝 */
    RACTuple *tuple3 = RACTuplePack(@"1", @"2", @"3", @"4", @"5");
    
    NSLog(@"取元祖內(nèi)容:%@", tuple1[0]);
    NSLog(@"第一個元素:%@", [tuple2 first]);
    NSLog(@"最后一個元素:%@", [tuple3 last]);

這里再說一下RACSequence這個集合類,用于代替NSArray, NSDictionary,可以使用它來快速遍歷數(shù)組和字典。

//遍歷數(shù)組
    /*
     遍歷原理:
     通過arr.rac_sequence把數(shù)據(jù)arr轉(zhuǎn)化成集合RACSequence
     通過arr.rac_sequence.signal把集合RACSequence轉(zhuǎn)化成了信號
     *通過subscribeNext訂閱信號裆站,遍歷集合
     */
    NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];
    [array.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"數(shù)組內(nèi)容:%@", x); // x 可以是任何對象
    }];


    /* 遍歷字典 */
    //遍歷字典,遍歷出來的鍵值對會包裝成RACTuple(元組對象)
    NSDictionary *dictionary = @{@"key1":@"value1", @"key2":@"value2", @"key3":@"value3"};
    [dictionary.rac_sequence.signal subscribeNext:^(RACTuple * _Nullable x) {
       //RACTupleUnpack是一個宏定義
        RACTupleUnpack(NSString *key, NSString *value) = x; // x 是一個元祖条辟,這個宏能夠?qū)?key 和 value 拆開
        NSLog(@"字典內(nèi)容:%@:%@", key, value);
    }];


//下面兩個方法都是將數(shù)組內(nèi)容全部換為 0 ,第一個是單個操作宏胯,第二個是一次性全部替換羽嫡,兩個方法都不會改變原數(shù)組內(nèi)容,操作完后都會生成一個新的數(shù)組肩袍,省去了創(chuàng)建可變數(shù)組然后遍歷出來單個添加的步驟杭棵。
    /* 內(nèi)容操作 */
    NSArray *array1 = @[@"1", @"2", @"3", @"4", @"5"];
    NSArray *newArray1 = [[array1.rac_sequence map:^id _Nullable(id  _Nullable value) {
        
        NSLog(@"數(shù)組內(nèi)容:%@", value);
        
        return @"0"; // 將所有內(nèi)容替換為 0
        
    }] array];


    /* 內(nèi)容快速替換 */
    NSArray *array2 = @[@"1", @"2", @"3", @"4", @"5"];
    NSArray *newArray2 = [[array.rac_sequence mapReplace:@"0"] array]; // 將所有內(nèi)容替換為 0
5. 代理
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"標題" message:@"123456" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"other", nil];
//可以省去監(jiān)聽以及設(shè)置 delegate 的步驟
    [[self rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)] subscribeNext:^(RACTuple *tuple) {
        NSLog(@"%@",tuple.first);
        NSLog(@"%@",tuple.second);
        NSLog(@"%@",tuple.third);
    }];
    [alertView show];
6. 通知
//RAC將收到通知后的方法封裝成了block,省去了在 dealloc 中清除通知和監(jiān)聽通知創(chuàng)建方法的步驟。
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification *notification) {
        NSLog(@"%@", notification.name);
        NSLog(@"%@", notification.object);
    }];
7. KVO
    UIScrollView *scrolView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    scrolView.contentSize = CGSizeMake(200, 800);
    scrolView.backgroundColor = [UIColor redColor];
    [self.view addSubview:scrolView];

    //原生,其缺點是當(dāng)你需要觀察很多屬性時,你要寫很多次下面的方法,而且在觀察的方法中還要去判斷KeyPath具體是什么
    [scrolView addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];

    //RAC方式1  利用 RAC 的宏,只要對象的屬性發(fā)生改變就會產(chǎn)生信號
    [RACObserve(scrolView, contentOffset) subscribeNext:^(id x) {
        NSLog(@"contentOffset: %@",x);
    }];
    //RAC方式2
    [self.redView rac_observeKeyPath:@"frame" options:NSKeyValueObservingOptionNew observer:self block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
        
    }];
    //RAC方式3    先包裝成了一個信號,只要值改變就會發(fā)送信號氛赐。
    [[self.redView rac_valuesForKeyPath:@"frame" observer:self] subscribeNext:^(id  _Nullable x) {
        NSLog(@"frame屬性的改變1:%@", x); // x 是監(jiān)聽屬性的改變結(jié)果
    }];
8. 監(jiān)聽 TextField 的輸入改變
//可以省去設(shè)置 delegate 和實現(xiàn)代理方法的步驟魂爪。
    [[self.textField.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
        
        return value.length > 5; // 表示輸入文字長度 > 5 時才會調(diào)用下面的 block
        
    }] subscribeNext:^(NSString * _Nullable x) {
        
        NSLog(@"輸入框內(nèi)容:%@", x);
    }];
    
    [[self.textField.rac_textSignal map:^id(id value) {
        return [UIColor redColor];
    }] subscribeNext:^(id x) {
        //        NSLog(@"x:%@", x);
    }];
    
    
    [self.textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"輸入框內(nèi)容:%@", x);
    }];
    
    //給label同時賦值,其實就是用綁定信號的,只要產(chǎn)生信號內(nèi)容,就會把內(nèi)容給屬性賦值
    UILabel *label;
    RAC(label,text) = self.textField.rac_textSignal;
9. 添加手勢
//UIView
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]init];
    [tap.rac_gestureSignal subscribeNext:^(id x) {
        NSLog(@"x:%@", x);
        self.redView.backgroundColor = [UIColor yellowColor];
    }];
    [self.redView addGestureRecognizer: tap];
10. 監(jiān)聽 Button 點擊事件
//可以省去 addTarget 添加事件和創(chuàng)建方法的步驟。
    [[self.btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        NSLog(@"點擊了按鈕");
    }];


    //登錄按鈕狀態(tài)實時監(jiān)聽
    //下面表示只有 用戶名 和 密碼 輸入框內(nèi)容都大于 0 時艰管,登錄 按鈕才可以點擊滓侍,而且狀態(tài)是實時監(jiān)聽的,一句代碼就能完成這個功能蛙婴。
    RAC(self.btn, enabled) = [RACSignal combineLatest:@[self.textField.rac_textSignal, self.textField.rac_textSignal] reduce:^id _Nullable(NSString * username, NSString * password){
        
        return @(username.length && password.length);
    }];
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市尔破,隨后出現(xiàn)的幾起案子街图,更是在濱河造成了極大的恐慌,老刑警劉巖懒构,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件餐济,死亡現(xiàn)場離奇詭異,居然都是意外死亡胆剧,警方通過查閱死者的電腦和手機絮姆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來秩霍,“玉大人篙悯,你說我怎么就攤上這事×迦蓿” “怎么了鸽照?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長颠悬。 經(jīng)常有香客問我矮燎,道長定血,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任诞外,我火速辦了婚禮澜沟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘峡谊。我一直安慰自己茫虽,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布靖苇。 她就那樣靜靜地躺著席噩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪贤壁。 梳的紋絲不亂的頭發(fā)上悼枢,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機與錄音脾拆,去河邊找鬼馒索。 笑死,一個胖子當(dāng)著我的面吹牛名船,可吹牛的內(nèi)容都是我干的绰上。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼渠驼,長吁一口氣:“原來是場噩夢啊……” “哼蜈块!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起迷扇,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤百揭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蜓席,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體器一,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年厨内,在試婚紗的時候發(fā)現(xiàn)自己被綠了祈秕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡雏胃,死狀恐怖请毛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瞭亮,我是刑警寧澤获印,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響兼丰,放射性物質(zhì)發(fā)生泄漏玻孟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一鳍征、第九天 我趴在偏房一處隱蔽的房頂上張望黍翎。 院中可真熱鬧,春花似錦艳丛、人聲如沸匣掸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽碰酝。三九已至,卻和暖如春戴差,著一層夾襖步出監(jiān)牢的瞬間送爸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工暖释, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留袭厂,地道東北人。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓球匕,卻偏偏與公主長得像纹磺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子亮曹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容