ReactiveCocoa學習筆記整理(二)

此文章是ReactiveCocoa學習筆記的第二篇携添,未閱讀第一篇的童鞋,請先查閱第一篇ReactiveCocoa學習筆記整理(一) 闹蒜。好的芽卿,廢話不多說揭芍,上一篇中我們簡單的了解了RAC的概念,編程思想以及RACSignal這個基類的簡單應用卸例。我們接著上一篇的內(nèi)容繼續(xù)探尋RAC學習之路称杨。

三. RACSubject基礎知識點

首先,我們介紹另一個使用非常頻繁的類筷转,RACSubject姑原,我們將會從它的概念,使用步驟呜舒,底層實現(xiàn)入手锭汛,慢慢剖析,然后通過幾個簡單的小例子應用一下下袭蝗。

1. RACSubject基本概念以及使用步驟

RACSubject被稱為信號提供者店乐,它既可以自己充當信號,又能夠發(fā)送信號呻袭。最常用的使用場景就是用來代替代理,有了它腺兴,就沒必要定義代理了左电。接下來,我們看一下RACSubject的具體使用步驟:

  1. 創(chuàng)建信號 [RACSubject subject]页响,跟RACSiganl不一樣篓足,創(chuàng)建信號時沒有block。
  2. 訂閱信號 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
  3. 發(fā)送信號 sendNext:(id)value

2. RACSubject底層實現(xiàn)以及簡單應用

RACSubject的底層實現(xiàn)和RACSignal不一樣闰蚕,簡單的介紹一下RACSubject的實現(xiàn)步驟栈拖。

  1. 調(diào)用subscribeNext訂閱信號,只是把訂閱者保存起來没陡,并且訂閱者的nextBlock已經(jīng)賦值了
  2. 調(diào)用sendNext發(fā)送信號涩哟,遍歷剛剛保存的所有訂閱者,一個一個調(diào)用訂閱者的nextBlock
    在這篇文章就不展開描述了盼玄,有興趣的童鞋可以查閱ReactiveCocoa深入理解 贴彼,里面有關于底層實現(xiàn)的詳細剖析。這里需要對持有訂閱者解釋一下埃儿,由于RACSubject是熱信號, 為了保證未來有事件發(fā)生的時候, 訂閱者可以收到信息, 所以需要持有訂閱者器仗。好了,我們用簡單的小實例探究一下,請看如下代碼:
RACSubject *subject=[RACSubject subject];
    
    [subject subscribeNext:^(id x) {
        NSLog(@"訂閱者1的值%@",x);
    }];
    
    [subject sendNext:@"wujunyang"];
    
    [subject subscribeNext:^(id x) {
        NSLog(@"訂閱者2的值%@",x);
    }];
    
    [subject sendNext:@"cnblogs"];
    
//    輸出:
//    訂閱者1的值wujunyang
//    訂閱者1的值cnblogs
//    訂閱者2的值cnblogs

通過以后的代碼輸出精钮,我們可以很明確的得到結論:RACSubject 發(fā)送過了sendNext威鹿, 下面再去監(jiān)聽它是沒有效果,即RACSubject是熱信號的本質轨香。
上面也提到了忽你,RACSubject最常用的使用場景就是用來代替代理,接下來我們寫一個小的需求來看一下是如何實現(xiàn)的代替代理弹沽。目前檀夹,我們有這樣一個需求:

  • 給當前控制器添加一個按鈕,modal到另一個控制器界面
  • 另一個控制器view中有個按鈕策橘,點擊按鈕炸渡,通知當前控制器
    我們用RACSubject可以這樣來實現(xiàn):
 
    @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 {
        
        // 創(chuàng)建第二個控制器
        TwoViewController *twoVc = [[TwoViewController alloc] init];
        
        // 設置代理信號
        twoVc.delegateSignal = [RACSubject subject];
        
        // 訂閱代理信號
        [twoVc.delegateSignal subscribeNext:^(id x) {
            
            NSLog(@"點擊了通知按鈕");
        }];
        
        // 跳轉到第二個控制器
        [self presentViewController:twoVc animated:YES completion:nil];
        
    }
    @end

在上述代碼中,大致分為三個步驟:

  1. 在第二個控制器.h沛婴,添加一個RACSubject代替代理
  2. 監(jiān)聽第二個控制器按鈕點擊
  3. 在第一個控制器中吼畏,監(jiān)聽跳轉按鈕,給第二個控制器的代理信號賦值,并且監(jiān)聽
    你看蚜点,用RACSubject代替代理就是這么簡單滴就實現(xiàn)啦溃睹。

3. RACReplaySubject簡單介紹以及應用

既然講到了RACSubject,那么久一起把它的子類RACReplaySubject順便說了吧... RACReplaySubject是重復提供信號類性雄,它的使用場景一般有以下兩個:

  • 如果一個信號每被訂閱一次,就需要把之前的值重復發(fā)送一遍羹奉,使用重復提供信號類
  • 可以設置 capacity 數(shù)量來限制緩存的 value 的數(shù)量,即只緩充最新的幾個值
    RACReplaySubject的創(chuàng)建方法也很簡單明了秒旋,首先創(chuàng)建RACReplaySubject,然后訂閱信號诀拭,最后發(fā)送信號迁筛。而它的工作流程可以大致分為以下的三步:
  1. 訂閱信號時,內(nèi)部保存了訂閱者耕挨,和訂閱者響應block
  2. 當發(fā)送信號時细卧,遍歷訂閱者,調(diào)用訂閱者的nextBlock
  3. 發(fā)送的信號會保存起來筒占,當訂閱者訂閱信號時酒甸,會將之前保存的信號,一個一個遍歷
    最后赋铝,我們通過簡單的小例子來看一下它的使用:
    RACReplaySubject *replaySubject = [RACReplaySubject subject];
    [replaySubject subscribeNext:^(id x) {
        NSLog(@"1 %@,type:%@",x,NSStringFromClass(object_getClass(x)));
    }];
    [replaySubject subscribeNext:^(id x) {
        NSLog(@"1 %@,type:%@",x,NSStringFromClass(object_getClass(x)));
    }];
    [replaySubject sendNext:@1];
    
    [replaySubject subscribeNext:^(id x) {
        NSLog(@"3 %@,type:%@",x,NSStringFromClass(object_getClass(x)));
    }];

    //輸出
//    1 1,type:__NSCFNumber
//    1 1,type:__NSCFNumber
//    3 1,type:__NSCFNumber

通過上面的代碼插勤,我們可以看出RACReplaySubject與RACSubject的區(qū)別,RACSubject必須要先訂閱信號之后才能發(fā)送信號,而RACReplaySubject可以先發(fā)送信號后訂閱农尖。

四. RACSequence以及RACTuple的基本簡介跟使用

啊哈哈析恋,在本章節(jié)我們將隆重的介紹RACSequence,它是RAC中的集合類盛卡,可以用于代替NSArray,NSDictionary,可以使用它來快速遍歷數(shù)組和字典助隧。我們就對數(shù)組的操作簡單的總結一下它的流程:

  1. 把數(shù)組轉換成集合RACSequence numbers.rac_sequence
  2. 把集合RACSequence轉換RACSignal信號類 numbers.rac_sequence.signal
  3. 訂閱信號,激活信號滑沧,會自動把集合中的所有值并村,遍歷出來
    NSArray *arr = @[@1,@2,@3,@4,@5,@6];
    [arr.rac_sequence.signal subscribeNext:^(id x) {
        
        NSLog(@"當前的值x:%@",x);
    }];
    //輸出
//    當前的值x:1
//    當前的值x:2
//    當前的值x:3
//    當前的值x:4
//    當前的值x:5
//    當前的值x:6
    
    
    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"jtd",@"name",@"man",@"sex",@"jx",@"jg", nil];
    [dict.rac_sequence.signal subscribeNext:^(id x) {
        RACTupleUnpack(NSString *key,NSString *value) = x;
        
        NSLog(@"key:%@,value:%@",key,value);
    }];
    //輸出:
//    key:name,value:jtd
//    key:sex,value:man
//    key:jg,value:jx

如以上代碼所示,就如此方便快捷的實現(xiàn)了對數(shù)組以及字典的遍歷操作滓技。同樣的也可以對轉化之后的數(shù)組進行諸如map,filter,reduce,skip,take,contact..等等操作哩牍,接下來,我們通過代碼來詳細看一下:

    NSArray *array=@[@(2),@(5),@(7),@(15)];
    RACSequence *sequence = [array rac_sequence];
    
    id mapData = [sequence map:^id(id value) {
        return @([value integerValue] * 2);
    }];
    NSLog(@"序列Map之后的數(shù)據(jù):%@",[mapData array]);
    
    id filterData = [sequence filter:^BOOL(id value) {
        return [value integerValue]%2 == 0;
    }];
    NSLog(@"序列Filter之后的數(shù)據(jù):%@",[filterData array]);
    
    id reduceData = [sequence foldLeftWithStart:@"" reduce:^id(id accumulator, id value) {
        return [accumulator stringByAppendingString:[value stringValue]];
    }];
    NSLog(@"序列Left-Reduce之后的數(shù)據(jù):%@",reduceData);
    
    id rightReduceData = [sequence foldRightWithStart:@"" reduce:^id(id first, RACSequence *rest) {
        return [NSString stringWithFormat:@"%@%@", rest.head, first];
    }];
    NSLog(@"序列Right-Reduce之后的數(shù)據(jù):%@",rightReduceData);
    
    id skipData = [sequence skip:1];
    NSLog(@"序列Skip之后的數(shù)據(jù):%@",[skipData array]);
    
    
    id takeData = [sequence take:2];
    NSLog(@"序列Take之后的數(shù)據(jù):%@",[takeData array]);
    
    id takeUntilData = [sequence takeUntilBlock:^BOOL(id x) {
        return [x integerValue] == 7;
    }];
    NSLog(@"序列TakeUntil之后的數(shù)據(jù):%@",[takeUntilData array]);
    
    NSArray *nextArr = @[@"A",@"B",@"C"];
    RACSequence *nextSequence = [nextArr rac_sequence];
    id contactData = [sequence concat:nextSequence];
    NSLog(@"FlyElephant序列Contact之后的數(shù)據(jù):%@",[contactData array]);

    //輸出
//    序列Map之后的數(shù)據(jù):(
//                                           4,
//                                           10,
//                                           14,
//                                           30
//                                           )
//    序列Filter之后的數(shù)據(jù):(
//                                                                      2
//                                                                      )
//    序列Left-Reduce之后的數(shù)據(jù):25715
//    序列Right-Reduce之后的數(shù)據(jù):15752
//    序列Skip之后的數(shù)據(jù):(
//                                                                    5,
//                                                                    7,
//                                                                    15
//                                                                    )
//    序列Take之后的數(shù)據(jù):(
//                                                                    2,
//                                                                    5
//                                                                    )
//    序列TakeUntil之后的數(shù)據(jù):(
//                                                                         2,
//                                                                         5
//                                                                         )
//    FlyElephant序列Contact之后的數(shù)據(jù):(
//                                                                                  2,
//                                                                                  5,
//                                                                                  7,
//                                                                                  15,
//                                                                                  A,
//                                                                                  B,
//                                                                                  C
//                                                                                  )

然后令漂,我們再來看一下RACTuple這個類膝昆,RACTuple是ReactiveCocoa的元組類,首先上圖看一下他的定義叠必。

@interface RACTuple : NSObject <NSCoding, NSCopying, NSFastEnumeration>

@property (nonatomic, readonly) NSUInteger count;

@property (nonatomic, readonly) id first;
@property (nonatomic, readonly) id second;
@property (nonatomic, readonly) id third;
@property (nonatomic, readonly) id fourth;
@property (nonatomic, readonly) id fifth;
@property (nonatomic, readonly) id last;
@property (nonatomic, strong) NSArray *backingArray;

@property (nonatomic, copy, readonly) RACSequence *rac_sequence; // 這個是專門為sequence提供的一個擴展

@end

可以看到荚孵,RACTuple的定義看上去很簡單,底層實質就是一個NSArray纬朝,只不過封裝了一些方法收叶。RACTuple繼承了NSCoding, NSCopying, NSFastEnumeration這三個協(xié)議,具體的協(xié)議就不做過多的解讀了共苛,本文本著 "如何使用" 來進行基礎講解判没,況且RACTuple的方法也不多,總共就6個方法俄讹,3個類方法,3個實例方法绕德。RACTuple有如下的優(yōu)點:

  • 可用下標訪問元素 (實現(xiàn)了objectAtIndexedSubscript:方法)
  • 可用for in枚舉(遵循NSFastEnumeration協(xié)議)
  • 可跟NSArray互相轉換
  • 可轉換為RACSequence
  • 可把NSNull.null轉為RACTupleNil.tupleNil
    我們通過簡單的實例來看一下用法患膛,請看如下代碼:
    //普通創(chuàng)建
    RACTuple *tuple1 = [RACTuple tupleWithObjects:@1, @2, @3, nil];
    RACTuple *tuple2 = [RACTuple tupleWithObjectsFromArray:@[@1, @2, @3]];
    RACTuple *tuple3 = [[RACTuple alloc] init];
    
    //宏創(chuàng)建
    RACTuple *tuple4 = RACTuplePack(@1, @2, @3, @4);
    
    //解包(等號前面是參數(shù)定義,后面是已存在的Tuple耻蛇,參數(shù)個數(shù)需要跟Tuple元素相同)
    RACTupleUnpack(NSNumber * value1, NSNumber * value2, NSNumber * value3, NSNumber * value4) = tuple4;
    NSLog(@"%@ %@ %@ %@", value1, value2, value3, value4);
    
    //元素訪問方式
    NSLog(@"%@", [tuple4 objectAtIndex:1]);
    NSLog(@"%@", tuple4[1]);
    
    //輸出
    //1 2 3 4
    //2
    //2

好了踪蹬,今天的文章就到此吧,接下來的文章臣咖,我們將要探討一下RACCommand以及簡單的UIKit的實際運用跃捣,下篇文章見。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末夺蛇,一起剝皮案震驚了整個濱河市疚漆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖娶聘,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闻镶,死亡現(xiàn)場離奇詭異,居然都是意外死亡丸升,警方通過查閱死者的電腦和手機铆农,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來狡耻,“玉大人墩剖,你說我怎么就攤上這事∫恼” “怎么了岭皂?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長孵淘。 經(jīng)常有香客問我蒲障,道長,這世上最難降的妖魔是什么瘫证? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任揉阎,我火速辦了婚禮,結果婚禮上背捌,老公的妹妹穿的比我還像新娘毙籽。我一直安慰自己,他們只是感情好毡庆,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布坑赡。 她就那樣靜靜地躺著,像睡著了一般么抗。 火紅的嫁衣襯著肌膚如雪毅否。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天蝇刀,我揣著相機與錄音螟加,去河邊找鬼。 笑死吞琐,一個胖子當著我的面吹牛捆探,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播站粟,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼黍图,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了奴烙?” 一聲冷哼從身側響起助被,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤剖张,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后恰起,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體修械,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年检盼,在試婚紗的時候發(fā)現(xiàn)自己被綠了肯污。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡吨枉,死狀恐怖蹦渣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情貌亭,我是刑警寧澤柬唯,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站圃庭,受9級特大地震影響锄奢,放射性物質發(fā)生泄漏。R本人自食惡果不足惜剧腻,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一拘央、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧书在,春花似錦灰伟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至栈源,卻和暖如春挡爵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背甚垦。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工茶鹃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人制轰。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓前计,卻偏偏與公主長得像胞谭,于是被迫代替她去往敵國和親垃杖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

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