RAC(ReactiveCocoa)

ReactiveCocoa是iOS開(kāi)發(fā)的一個(gè)開(kāi)源第三方框架杨何,又被稱(chēng)作函數(shù)響應(yīng)是編程框架净赴。它結(jié)合了函數(shù)式編程響應(yīng)式編程兩種編程風(fēng)格俺亮,定義了一個(gè)標(biāo)準(zhǔn)的接口來(lái)響應(yīng)諸如點(diǎn)擊按鈕驮捍,網(wǎng)絡(luò)請(qǐng)求完成等事件。

函數(shù)式編程&響應(yīng)式編程

  • 何謂函數(shù)式編程

函數(shù)式編程就是把操作任務(wù)盡量寫(xiě)成一系列嵌套的函數(shù)或方法來(lái)調(diào)用脚曾。
這種編程思想有幾個(gè)特點(diǎn):方法的返回值是他本身东且,參數(shù)是Block,如果對(duì)block不太熟悉的同學(xué),可以先看一下這篇文章:iOS Block本讥,做一下了解苇倡。

  • 何謂響應(yīng)式編程

我們可以用KVO來(lái)理解響應(yīng)式編程。一個(gè)類(lèi)中有一個(gè)user對(duì)象囤踩,user有“userId”“userName”兩個(gè)屬性旨椒,我們利用KVO來(lái)觀察user的userName屬性,當(dāng)userName屬性變化了的時(shí)候堵漱,會(huì)執(zhí)行下面的方法综慎。

#import "HomeViewController.h"
#import "User.h"

@interface HomeViewController ()
@property (nonatomic, strong) User *user;
@end

@implementation HomeViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.user = [User new];
    self.user.userName = @"張三";
    self.user.userId = 10086;
    [self.user addObserver:self forKeyPath:@"userName" options:
    |NSKeyValueObservingOptionNew context:nil];
        NSLog(@"%@", self.user);
        self.user.userName = @"李四";
        self.user.userId = 10010;
    }
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
       NSLog(@"%@%ld", self.user.userName, self.user.userId);
}

添加ReactiveCocoa到工程

和其他的第三方一樣,添加ReactiveCocoa的方式有兩種:

  • 通過(guò)CocoaPods添加
#RAC
pod 'ReactiveCocoa', '~> 2.5'
  • 通過(guò)GitHub手動(dòng)下載ReactiveCocoa勤庐,根據(jù)文檔添加到工程示惊。

ReactiveCocoa常用的類(lèi)

1. RACSignal(信號(hào))

RACSignal是RAC中最核心的類(lèi),如果把它學(xué)懂了愉镰, 就已經(jīng)可以用ReactiveCocoa進(jìn)行開(kāi)發(fā)了米罚。

可以將RACSingnal當(dāng)做一個(gè)傳遞信號(hào)的工具,當(dāng)數(shù)據(jù)變化的時(shí)候丈探,會(huì)將改變的信息發(fā)送出去录择,訂閱者接受到這個(gè)信息,執(zhí)行相應(yīng)的方法碗降。

信號(hào)我們將它分為兩種:一種是冷信號(hào)隘竭,也是默認(rèn)的信號(hào),這種信號(hào)讼渊,即使數(shù)據(jù)改變了动看,也不會(huì)發(fā)送信息;當(dāng)有訂閱者訂閱了這個(gè)信號(hào)爪幻,它才會(huì)變成熱信號(hào)菱皆,當(dāng)數(shù)據(jù)變化须误,它會(huì)將改變的數(shù)據(jù)發(fā)送出去,具體的,我們來(lái)看看RACSignal是怎么使用的:

    // 1 創(chuàng)建一個(gè)信號(hào)
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 3 發(fā)送數(shù)據(jù)
        [subscriber sendNext:@"第一個(gè)信號(hào)"]; 
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"取消信號(hào)");
        }];
    }];
    
    /*********** 到這里還是“冷信號(hào)” ***********/
    
    // 2 訂閱信號(hào)(冷信號(hào)變熱信號(hào))
    [signal subscribeNext:^(id x) {
        // 4 處理信號(hào)
        NSLog(@"%@", x);
    }];

這里面寫(xiě)了RACSignal基本的操作仇轻,信號(hào)的創(chuàng)建京痢,訂閱以及發(fā)送。

2. RACSubscriber

上面的代碼中我們還看到了兩個(gè)類(lèi)拯田,在創(chuàng)建信號(hào)時(shí)block返回的類(lèi)型 RACDisposable和參數(shù) RACSubscriber历造。
RACSubscriber:表示訂閱者的意思甩十,在通過(guò)creat創(chuàng)建信號(hào)的時(shí)候船庇,都會(huì)有一個(gè)訂閱者,來(lái)發(fā)送數(shù)據(jù)侣监。

3. RACDisposable

RACDisposable:是用來(lái)取消訂閱鸭轮、清理資源的。
這里我們還有一種寫(xiě)法橄霉,來(lái)手動(dòng)取消訂閱窃爷,這種情況,我們需要先來(lái)實(shí)例化個(gè)對(duì)象再來(lái)調(diào)用dispose方法:

    // 訂閱信號(hào)
    RACDisposable *disposable = [signal subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
    // 取消訂閱
    [disposable dispose];
4. RACSubject & RACReplaySubject

RACSubject 是信號(hào)提供者姓蜂,它既可以充當(dāng)信號(hào)按厘,又可以發(fā)送信號(hào)

    // 1創(chuàng)建信號(hào)
    RACSubject *subject = [RACSubject subject];
    // 2訂閱信號(hào)
    [subject subscribeNext:^(id x) {
        // 4處理信號(hào)
        NSLog(@"訂閱:%@", x);
    }];
    // 3發(fā)送信號(hào)
    [subject sendNext:@"信號(hào)"];

RACReplaySubject:是RACSubject的子類(lèi),重復(fù)提供信號(hào)钱慢。

    // 創(chuàng)建信號(hào)
    RACReplaySubject *replaySubject = [RACReplaySubject subject];
    // 發(fā)送信號(hào)
    [replaySubject sendNext:@"信號(hào)1"];
    // 訂閱信號(hào)
    [replaySubject subscribeNext:^(id x) {
                NSLog(@"訂閱1:%@", x);
    }];
    // 發(fā)送信號(hào)
    [replaySubject sendNext:@"信號(hào)2"];
    // 訂閱信號(hào)
    [replaySubject subscribeNext:^(id x) {
                NSLog(@"訂閱2:%@", x);
    }];

RACReplaySubject和RACSubject的最大的區(qū)別在于:
RACReplaySubject既可以先發(fā)送信號(hào)再訂閱逮京,也可以先訂閱信號(hào),再發(fā)送束莫;而RACSubject只能先訂閱信號(hào)懒棉,再發(fā)送。

5.RACTuple(元組)

在Objective-C中览绿,本身是沒(méi)有元組的策严,在Swift中有元組的概念。它與數(shù)組類(lèi)似饿敲,可以以數(shù)組來(lái)初始化:

    NSArray *arr = @[@"張三", @"10086", @"boy"];
    RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:arr];
    NSLog(@"\nname:%@\nid:%@\ngender:%@", [tuple objectAtIndex:0], [tuple objectAtIndex:1], [tuple objectAtIndex:2]);
執(zhí)行結(jié)果

ReactiveCocoa常用的方法

1. 監(jiān)聽(tīng)事件

// 1. 監(jiān)聽(tīng)事件
    [[self.bt_Go rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
        NSLog(@"被點(diǎn)擊");
        HomeViewController_2 *vc_2 = [[HomeViewController_2 alloc] initWithNibName:@"HomeViewController_2" bundle:nil];
        vc_2.hidesBottomBarWhenPushed = YES;
        [self.navigationController pushViewController:vc_2 animated:YES];

    }];

2. 監(jiān)聽(tīng)通知

// 2. 監(jiān)聽(tīng)通知
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"socketMessage" object:nil] subscribeNext:^(id x) {
        NSLog(@"收到!");
    }];

3. 監(jiān)聽(tīng)TextField的變化

// 3. 監(jiān)聽(tīng)TextField變化
    [self.tx_userName.rac_textSignal subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];

4. 監(jiān)聽(tīng)變量屬性(KVO)

// 4. 監(jiān)聽(tīng)變量屬性
    self.user = [User new];
    self.user.userId = 10086;
    self.user.userName = @"張三";
    [[self.user rac_valuesForKeyPath:@"userName" observer:nil] subscribeNext:^(id x) {
        NSLog(@"用戶(hù)的名字改變了:%@", x);
    }];
    self.user.userName = @"李四";

5. 充當(dāng)代理

// 5. 充當(dāng)代理
    self.headerView = [[[NSBundle mainBundle] loadNibNamed:@"HomeHeaderView" owner:self options:nil] lastObject];
    self.headerView.frame = CGRectMake(0, SCREEN_HEIGHT - 300, SCREEN_WIDTH, 300);
    [self.view addSubview:self.headerView];
    [self.headerView.subject subscribeNext:^(User *user) {
        NSLog(@"收到信號(hào):\n用戶(hù)名:%@妻导,用戶(hù)id:%ld", user.userName, user.userId);
    }];

ReactiveCocoa常用的宏

1. RAC(TARGET, ...)

1.1 用途:

用來(lái)將某個(gè)對(duì)象的某個(gè)屬性和某個(gè)信號(hào)綁定。當(dāng)有信號(hào)過(guò)來(lái)怀各,會(huì)自動(dòng)賦值給對(duì)象的屬性栗竖。

1.2 用法:
// lb_name 是一個(gè)UILable, tx_userName是UITextField
RAC(self.lb_name, text) = self.tx_userName.rac_textSignal;
1.3 對(duì)比:

我們實(shí)現(xiàn)以下渠啤,在一個(gè)textfield中輸入內(nèi)容時(shí)狐肢,將它實(shí)時(shí)輸入到一個(gè)label中,看看以下幾種方法是怎么實(shí)現(xiàn)的沥曹,哪個(gè)更簡(jiǎn)單份名。

  • 不用RAC碟联,通過(guò)給TextField添加方法來(lái)實(shí)現(xiàn)
- (void)viewDidLoad {
    [super viewDidLoad];
    [self.tx_userName addTarget:self action:@selector(showtextFiledContents) forControlEvents:UIControlEventEditingChanged];
}
- (void) showtextFiledContents{
    self.lb_label1.text = self.tx_userName.text;
}

  • 利用RAC綁定屬性和信號(hào)
    [self.tx_userName.rac_textSignal subscribeNext:^(NSString *x) {
        self.lb_label1.text = x;
    }];
  • 用RAC(TARGET, ...)實(shí)現(xiàn)
    RAC(self.lb_label1, text) = self.tx_userName.rac_textSignal;

2. RACObserve(TARGET, KEYPATH)

2.1 用途:

監(jiān)聽(tīng)某個(gè)對(duì)象的某個(gè)屬性,實(shí)際上它是[target_ rac_valuesForKeyPath:@keypath(TARGET, KEYPATH) observer:self]這句代碼的宏

2.2 用法
    [RACObserve(self.user, userName) subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
2.3 對(duì)比

實(shí)現(xiàn)監(jiān)聽(tīng)user的userName屬性

  • 不使用 RACObserve僵腺,直接監(jiān)聽(tīng)
    self.user = [User new];
    self.user.userId = 10086;
    self.user.userName = @"張三";

    [[self.user rac_valuesForKeyPath:@"userName" observer:nil] subscribeNext:^(id x) {
        NSLog(@"用戶(hù)的名字改變了:%@", x);
    }];
    
    [[self.bt_Go rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
        self.user.userName = @"李四";
    }];
  • 使用 RACObserve
    self.user = [User new];
    self.user.userId = 10086;
    self.user.userName = @"張三";
        
    [RACObserve(self.user, userName) subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
    
    [[self.bt_Go rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
        self.user.userName = @"李四";
    }];

3. @weakify(Obj)和@strongify(Obj)

3.1用途:

防止循環(huán)引用

3.2 用法:

@weakify(Obj)和@strongify(Obj)是配合使用的鲤孵,@weakify(Obj)寫(xiě)在block外,@strongify(Obj)寫(xiě)在block內(nèi)

@weakify(self)
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        @strongify(self)
        [subscriber sendNext:self];
        return nil;
    }];
    
    [signal subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];

4. RACTuplepack

用途:

把數(shù)據(jù)包裝成RACTuple(元組類(lèi))

用法:
RACTuple *tuple = RACTuplePack(@"123",@1);

5. RACTupleUnpack

用途:

把RACTuple(元組類(lèi))解包成對(duì)應(yīng)的數(shù)據(jù)

用法:
RACTupleUnpack(NSString *str,NSNumber *num) = tuple;
NSLog(@"%@ %@",str,num);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末辰如,一起剝皮案震驚了整個(gè)濱河市普监,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌琉兜,老刑警劉巖凯正,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異豌蟋,居然都是意外死亡廊散,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)梧疲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)允睹,“玉大人,你說(shuō)我怎么就攤上這事幌氮$允埽” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵该互,是天一觀的道長(zhǎng)米者。 經(jīng)常有香客問(wèn)我,道長(zhǎng)慢洋,這世上最難降的妖魔是什么塘雳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮普筹,結(jié)果婚禮上败明,老公的妹妹穿的比我還像新娘。我一直安慰自己太防,他們只是感情好妻顶,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著蜒车,像睡著了一般讳嘱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上酿愧,一...
    開(kāi)封第一講書(shū)人閱讀 49,079評(píng)論 1 285
  • 那天沥潭,我揣著相機(jī)與錄音,去河邊找鬼嬉挡。 笑死钝鸽,一個(gè)胖子當(dāng)著我的面吹牛汇恤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拔恰,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼因谎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了颜懊?” 一聲冷哼從身側(cè)響起财岔,我...
    開(kāi)封第一講書(shū)人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎河爹,沒(méi)想到半個(gè)月后匠璧,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昌抠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年患朱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鲁僚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片炊苫。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖冰沙,靈堂內(nèi)的尸體忽然破棺而出侨艾,到底是詐尸還是另有隱情,我是刑警寧澤拓挥,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布唠梨,位于F島的核電站,受9級(jí)特大地震影響侥啤,放射性物質(zhì)發(fā)生泄漏当叭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一盖灸、第九天 我趴在偏房一處隱蔽的房頂上張望蚁鳖。 院中可真熱鬧,春花似錦赁炎、人聲如沸醉箕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)讥裤。三九已至,卻和暖如春姻报,著一層夾襖步出監(jiān)牢的瞬間己英,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工吴旋, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留损肛,地道東北人寒亥。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像荧关,于是被迫代替她去往敵國(guó)和親溉奕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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

  • 1.ReactiveCocoa簡(jiǎn)介 ReactiveCocoa(簡(jiǎn)稱(chēng)為RAC),是由Github開(kāi)源的一個(gè)應(yīng)用于i...
    清蘂翅膀的技術(shù)閱讀 1,976評(píng)論 0 1
  • //聯(lián)系人:石虎QQ:1224614774昵稱(chēng):嗡嘛呢叭咪哄 一忍啤、RAC內(nèi)存管理 RAC會(huì)維護(hù)一個(gè)全局的信號(hào)集合加勤,...
    石虎132閱讀 796評(píng)論 1 6
  • ‘’哎呀哎呀哎呀哎呀‘’,這一連串的叫聲同波,從一個(gè)小學(xué)生的嘴里發(fā)出鳄梅。她那彎彎的眉毛下,長(zhǎng)著一顆水汪汪的大眼睛未檩,高挺的...
    笑笑湯姆貓閱讀 179評(píng)論 2 2
  • 很高興能跟大家認(rèn)識(shí)戴尸,也很感謝大家能來(lái)到這個(gè)課堂上,你們是幸運(yùn)的冤狡。同時(shí)孙蒙,你們又是不幸的。 幸運(yùn)的是悲雳,你選擇了...
    流年錦繡閱讀 218評(píng)論 0 0