RAC(ReactiveCocoa)

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

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

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

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

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

我們可以用KVO來理解響應(yīng)式編程。一個類中有一個user對象,user有“userId”“userName”兩個屬性,我們利用KVO來觀察user的userName屬性,當(dāng)userName屬性變化了的時候,會執(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的方式有兩種:

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

ReactiveCocoa常用的類

1. RACSignal(信號)

RACSignal是RAC中最核心的類,如果把它學(xué)懂了, 就已經(jīng)可以用ReactiveCocoa進行開發(fā)了。

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

信號我們將它分為兩種:一種是冷信號,也是默認(rèn)的信號,這種信號,即使數(shù)據(jù)改變了,也不會發(fā)送信息;當(dāng)有訂閱者訂閱了這個信號,它才會變成熱信號,當(dāng)數(shù)據(jù)變化,它會將改變的數(shù)據(jù)發(fā)送出去,具體的,我們來看看RACSignal是怎么使用的:

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

這里面寫了RACSignal基本的操作,信號的創(chuàng)建,訂閱以及發(fā)送。

2. RACSubscriber

上面的代碼中我們還看到了兩個類,在創(chuàng)建信號時block返回的類型 RACDisposable和參數(shù) RACSubscriber。
RACSubscriber:表示訂閱者的意思,在通過creat創(chuàng)建信號的時候,都會有一個訂閱者,來發(fā)送數(shù)據(jù)。

3. RACDisposable

RACDisposable:是用來取消訂閱、清理資源的。
這里我們還有一種寫法,來手動取消訂閱,這種情況,我們需要先來實例化個對象再來調(diào)用dispose方法:

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

RACSubject 是信號提供者,它既可以充當(dāng)信號,又可以發(fā)送信號

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

RACReplaySubject:是RACSubject的子類,重復(fù)提供信號。

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

RACReplaySubject和RACSubject的最大的區(qū)別在于:
RACReplaySubject既可以先發(fā)送信號再訂閱,也可以先訂閱信號,再發(fā)送;而RACSubject只能先訂閱信號,再發(fā)送。

5.RACTuple(元組)

在Objective-C中,本身是沒有元組的,在Swift中有元組的概念。它與數(shù)組類似,可以以數(shù)組來初始化:

    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)聽事件

// 1. 監(jiān)聽事件
    [[self.bt_Go rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
        NSLog(@"被點擊");
        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)聽通知

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

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

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

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

// 4. 監(jiān)聽變量屬性
    self.user = [User new];
    self.user.userId = 10086;
    self.user.userName = @"張三";
    [[self.user rac_valuesForKeyPath:@"userName" observer:nil] subscribeNext:^(id x) {
        NSLog(@"用戶的名字改變了:%@", 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(@"收到信號:\n用戶名:%@,用戶id:%ld", user.userName, user.userId);
    }];

ReactiveCocoa常用的宏

1. RAC(TARGET, ...)

1.1 用途:

用來將某個對象的某個屬性和某個信號綁定。當(dāng)有信號過來,會自動賦值給對象的屬性。

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

我們實現(xiàn)以下,在一個textfield中輸入內(nèi)容時,將它實時輸入到一個label中,看看以下幾種方法是怎么實現(xiàn)的,哪個更簡單。

  • 不用RAC,通過給TextField添加方法來實現(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綁定屬性和信號
    [self.tx_userName.rac_textSignal subscribeNext:^(NSString *x) {
        self.lb_label1.text = x;
    }];
  • 用RAC(TARGET, ...)實現(xiàn)
    RAC(self.lb_label1, text) = self.tx_userName.rac_textSignal;

2. RACObserve(TARGET, KEYPATH)

2.1 用途:

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

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

實現(xiàn)監(jiān)聽user的userName屬性

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

    [[self.user rac_valuesForKeyPath:@"userName" observer:nil] subscribeNext:^(id x) {
        NSLog(@"用戶的名字改變了:%@", 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)寫在block外,@strongify(Obj)寫在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(元組類)

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

5. RACTupleUnpack

用途:

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

用法:
RACTupleUnpack(NSString *str,NSNumber *num) = tuple;
NSLog(@"%@ %@",str,num);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 1.ReactiveCocoa簡介 ReactiveCocoa(簡稱為RAC),是由Github開源的一個應(yīng)用于i...
    清蘂翅膀的技術(shù)閱讀 2,014評論 0 1
  • //聯(lián)系人:石虎QQ:1224614774昵稱:嗡嘛呢叭咪哄 一、RAC內(nèi)存管理 RAC會維護一個全局的信號集合,...
    石虎132閱讀 809評論 1 6
  • ‘’哎呀哎呀哎呀哎呀‘’,這一連串的叫聲,從一個小學(xué)生的嘴里發(fā)出。她那彎彎的眉毛下,長著一顆水汪汪的大眼睛,高挺的...
    笑笑湯姆貓閱讀 192評論 2 2
  • 很高興能跟大家認(rèn)識,也很感謝大家能來到這個課堂上,你們是幸運的。同時,你們又是不幸的。 幸運的是,你選擇了...
    流年錦繡閱讀 227評論 0 0