之前我們初步認(rèn)識了RAC的設(shè)計思路跟實現(xiàn)方式, 現(xiàn)在我們再來看看如果使用它以及它能幫我們做什么

One of the major advantages of RAC is that it provides a single, unified approach to dealing with asynchronous behaviors, including delegate methods, callback blocks, target-action mechanisms, notifications, and KVO.

官方是這樣說的, RAC為我們提供了簡單便捷實現(xiàn)代理 / block回調(diào) / 事件 / 通知 / KVO的方式

 

我們先看RAC如何幫助我們快速實現(xiàn)KVO

首先我們新建一個Student類, 給它一個age的屬性

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

#import <Foundation/Foundation.h>@interface Student : NSObject

@property (nonatomic, strong) NSString *age;@end

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

下面我們看一個簡單的如何使用RAC來實現(xiàn)KVO

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

    Student *stu = [[Student alloc] init];    
    // RAC KVO
    [RACObserve(stu, age) subscribeNext:^(id  _Nullable x) {
        
        NSLog(@"stu的age改變?yōu)? %@", x);
    }];
    
    stu.age = @"10";

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

運行看看:

2017-07-23 11:35:19.704 RAC[67362:13075201] stu的age改變?yōu)? (null)2017-07-23 11:35:19.704 RAC[67362:13075201] stu的age改變?yōu)? 10

很方便對吧, 不用我們?nèi)dd observe, 不用出來觀察事件, 也不用我們?nèi)ヒ瞥P(guān)注

不過大家注意到了沒, 這里添加關(guān)注后block立即執(zhí)行了一次, 大家可以依據(jù)實際項目情況加個條件判斷做處理.

這里其實RAC還為我們提供了除了subscriber以外的操作,  后面再介紹給, 現(xiàn)在我們主要先來看RAC是怎么替我們做KVO的

 

我們再看看RAC如何幫我們實現(xiàn)target-action

我們創(chuàng)建一個項目, 在controller中添加一個button, 然后給button添加一個點擊事件

如果是常規(guī)寫法的話, 在創(chuàng)建完button后創(chuàng)建一個點擊響應(yīng)方法, 然后通過addTarget把響應(yīng)方法跟button及事件綁定到一起

大概類似這樣:

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

[button addTarget:self action:@selector(btnAction) forControlEvents:UIControlEventTouchUpInside];- (void)btnAction {
    
    NSLog(@"點擊了按鈕");
}

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

在上一篇我們提到過這樣的劣勢, 當(dāng)代碼比較多的時候結(jié)構(gòu)容易亂, 維護的時候也不好查找方法

我們看看RAC如何幫我們優(yōu)雅的實現(xiàn)

RAC為我們提供了rac_signalForControlEvents來處理UIControllerEvent, 我們試試看

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

    [[button
      rac_signalForControlEvents:UIControlEventTouchUpInside]
      subscribeNext:^(__kindof UIControl * _Nullable x) {
          
          NSLog(@"%@", x);
      }];

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

因為不知道這里的x是什么, 我們直接打印看看結(jié)果

2017-07-23 12:05:59.654 RAC[67611:13189769] <UIButton: 0x7f95e0d069f0; frame = (157 350.5; 100 35); opaque = NO; layer = <CALayer: 0x6080000269a0>>

當(dāng)我們點擊按鈕打印了上面這些,  是我們創(chuàng)建的button對象

那么加入需要點擊的時候給button更換背景圖片或者標(biāo)題就可以在這里處理了, 我們用改變顏色舉例

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

    [[button
      rac_signalForControlEvents:UIControlEventTouchUpInside]
      subscribeNext:^(__kindof UIControl * _Nullable x) {
          
          x.backgroundColor = [UIColor redColor];
      }];

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

運行后, 就可以看到如果點擊按鈕背景就會變成紅色, 如果有點擊事件也可以放在這里

但如果點擊后要處理的邏輯比較多, 代碼超過三行建議大家單獨寫一個方法供調(diào)用, 以免破壞代碼的結(jié)構(gòu)

RAC這樣的使用方式, 讓我的代碼邏輯更加清晰緊湊了, 我們再看一個添加手勢的例子

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
    
    [[tap
     rac_gestureSignal]
     subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
         
         NSLog(@"點擊了屏幕");
         NSLog(@"x: %@", x);
     }];
    
    [self.view addGestureRecognizer:tap];

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

運行看看:

2017-07-23 12:15:59.246 RAC[67766:13231274] 點擊了屏幕2017-07-23 12:15:59.247 RAC[67766:13231274] x: <UITapGestureRecognizer: 0x6000001a5160; state = Ended; view = <UIView 0x7fb932d03780>; target= <(action=sendNext:, target=<RACPassthroughSubscriber 0x60800003a920>)>>

這里x是一個手勢, 我們可以直接拿來使用, 比如我們改變下添加手勢這個view的顏色

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
    
    [[tap
     rac_gestureSignal]
     subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
         
         NSLog(@"點擊了屏幕");
         NSLog(@"x: %@", x);
         x.view.backgroundColor = [UIColor redColor];
     }];
    
    [self.view addGestureRecognizer:tap];

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

這樣手勢的初始化, 方法等等都在一起, 讓代碼一目了然

 

接下來我們看看RAC如何幫我們實現(xiàn)通知的

我們常規(guī)的通知應(yīng)該是這樣, 在要接收通知的地方添加關(guān)注通知并寫上通知事件

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notiAction) name:@"noti" object:nil];- (void)notiAction {
    
    NSLog(@"接到了通知");
}

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

然后在對應(yīng)的地方發(fā)送通知

[[NSNotificationCenter defaultCenter] postNotificationName:@"noti" object:nil userInfo:nil];

RAC會怎么幫我們實現(xiàn)呢?

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

    [[[NSNotificationCenter defaultCenter]
     rac_addObserverForName:@"noti" object:nil]
     subscribeNext:^(NSNotification * _Nullable x) {
         
         NSLog(@"接到了通知");
     }];

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

發(fā)送通知iOS已經(jīng)很簡單了, RAC沒有做重復(fù)工作但幫我們把添加關(guān)注通知的方法改進了, 可以讓事件和通知關(guān)注在一起

這樣接口就清晰了

 

那么RAC如果幫我們實現(xiàn)代理呢?

我用UIAlertView給大家舉個例子, 雖然蘋果已經(jīng)不推薦用這個 不過我們拿來當(dāng)例子用用看

先寫一個常規(guī)的AlertView

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

#import "ViewController.h"#import <ReactiveObjC.h>@interface ViewController ()<UIAlertViewDelegate>@end@implementation ViewController- (void)viewDidLoad {
    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.    
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"RAC" message:@"RAC Delegate Test" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil];
    
    [alertView show];
    
}- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {    
    if (buttonIndex == 0) {
        
        NSLog(@"點擊了Cancel按鈕");
    } else {
        
        NSLog(@"點擊了Ok按鈕");
    }
}@end

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

初始化alertView, 實現(xiàn)代理方法 這是我們常規(guī)的用法

那么我們再看看RAC如何做

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

#import "ViewController.h"#import <ReactiveObjC.h>@interface ViewController ()<UIAlertViewDelegate>@end@implementation ViewController- (void)viewDidLoad {
    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.    
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"RAC" message:@"RAC Delegate Test" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil];
    
    [[self
     rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)]
     subscribeNext:^(RACTuple * _Nullable x) {
         
         NSLog(@"%@", x);
     }];
    
    [alertView show];
    
}@end

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

RAC為我們提供了一個rac_signalForSelector: fromProtoc方法幫我們實現(xiàn)代理

我們把x打印看看

2017-07-23 12:53:07.138 RAC[68380:13356332] <RACTuple: 0x6080000149f0> (    "<UIAlertView: 0x7fc7dfc0c620; frame = (0 0; 0 0); layer = <CALayer: 0x6000002218a0>>",    1)

我們看看這個RACTuple

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

@interface RACTuple : NSObject <NSCoding, NSCopying, NSFastEnumeration>@property (nonatomic, readonly) NSUInteger count;/// These properties all return the object at that index or nil if the number of 
/// objects is less than the index.@property (nonatomic, readonly, nullable) id first;
@property (nonatomic, readonly, nullable) id second;
@property (nonatomic, readonly, nullable) id third;
@property (nonatomic, readonly, nullable) id fourth;
@property (nonatomic, readonly, nullable) id fifth;
@property (nonatomic, readonly, nullable) id last;

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

打印看看

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"RAC" message:@"RAC Delegate Test" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil];
    
    [[self
     rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)]
     subscribeNext:^(RACTuple * _Nullable x) {
         
         NSLog(@"%@", x);
         NSLog(@"first: %@", x.first);
         NSLog(@"second: %@", x.second);
         NSLog(@"third: %@", x.third);
         NSLog(@"fourth: %@", x.fourth);
         NSLog(@"fifth: %@", x.fifth);
         NSLog(@"last: %@", x.last);
     }];
    
    [alertView show];

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

結(jié)果為:

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

2017-07-23 16:29:26.089 RAC[68525:13409884] first: <UIAlertView: 0x7f814e604420; frame = (0 0; 0 0); layer = <CALayer: 0x60800003a3e0>>2017-07-23 16:29:26.090 RAC[68525:13409884] second: 12017-07-23 16:29:26.090 RAC[68525:13409884] third: (null)2017-07-23 16:29:26.090 RAC[68525:13409884] fourth: (null)2017-07-23 16:29:26.091 RAC[68525:13409884] fifth: (null)2017-07-23 16:29:26.091 RAC[68525:13409884] last: 1

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

第一個是alert本身, 第二個是index, 然后可以按我們的需要做處理了

 

另外要注意的是用RAC寫代理是有局限的,它只能實現(xiàn)返回值為void的代理方法

 

先到這里, 現(xiàn)在我們知道我們能用RAC做什么了

下次我們繼續(xù)看RAC的具體用法

http://www.cnblogs.com/zhouxihi/p/7225341.html