ReactiveCocoa(RAC)框架

简介

什么是RAC?ReactiveCocoa(简称RAC),是由Github开源的一个应用于iOS和OS开发的新框架,Cocoa是苹果整套框架的简称,因此很多苹果框架喜欢以Cocoa结尾。借用RayWenderlich上面的话:

As an iOS developer, nearly every line of code you write is in reaction to some event; a button tap, a received network message, a property change (via Key Value Observing) or a change in user’s location via CoreLocation are all good examples. However, these events are all encoded in different ways; as actions, delegates, KVO, callbacks and others. ReactiveCocoa defines a standard interface for events, so they can be more easily chained, filtered and composed using a basic set of tools.

翻译过来就是:

作为一个iOS开发者,你写的每一行代码几乎都是在响应某个事件,例如按钮的点击,收到网络消息,属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation)
。但是这些事件都用不同的方式来处理,比如action、delegate、KVO、callback等
。ReactiveCocoa为事件定义了一个标准接口,从而可以使用一些基本工具来更容易的连接、过滤和组合。

RAC是由Matt Thompson大神开发的,很多开发者对其的评价是开启一个新的Objective-C纪元。

  • 以下是RAC的Github主页:ReactiveCocoa
  • 以及官方给出的用法链接

安装

ReactiveCocoa用pod安装即可。
本文的Demo可在文章最后下载,在阅读本文的时候,强烈推荐边看Demo边看博文。
项目中加入了ReactiveCocoa和DeveloperLx的打印插件LxDBAnything同时加入了键盘相应的第三方IQKeyboardManager,以及Masonry,使用方法可以看这篇文章:iOS – Masonry自动布局(Autolayout)。

代码

第一部分 简单使用

文本框事件

原来我们在使用textFiled的时候我们需要写到

[textField addTarget:self action:@selector(textChanged:) forControlEvents:UIControlEventEditingChanged];

然后实现textChanged:方法,在RAC中,对于文本框的监听,是非常简单的一件事情,看如下代码:

UITextField * textField = ({
       UITextField * textField = [[UITextField alloc]init];
       textField.backgroundColor = [UIColor cyanColor];
       
       textField;
   });
  [self.view addSubview:textField];
   
   @weakify(self); //  __weak __typeof__(self) self_weak_ = self;
   
   [textField mas_makeConstraints:^(MASConstraintMaker *make) {
       
       @strongify(self);    // __strong __typeof__(self) self = self_weak_;
       make.size.mas_equalTo(CGSizeMake(180, 40));
       make.center.equalTo(self.view);
   }];
   
   [[textField rac_signalForControlEvents:UIControlEventEditingChanged]
    subscribeNext:^(id x) {
        
        LxDBAnyVar(x);
    }];
   [textField.rac_textSignal subscribeNext:^(NSString *x) {
       
       LxDBAnyVar(x);
   }];

打印结果:

__31-[ViewController textFiledTest]_block_invoke_2 + 215 x = 12
__31-[ViewController textFiledTest]_block_invoke241 + 211 x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '123'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0>; layer = 0x7fe810c51600>>
__31-[ViewController textFiledTest]_block_invoke_2 + 215 x = 123
__31-[ViewController textFiledTest]_block_invoke241 + 211 x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '1231'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0>; layer = 0x7fe810c51600>>
__31-[ViewController textFiledTest]_block_invoke_2 + 215 x = 1231
__31-[ViewController textFiledTest]_block_invoke241 + 211 x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '12312'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0>; layer = 0x7fe810c51600>>
__31-[ViewController textFiledTest]_block_invoke_2 + 215 x = 12312
__31-[ViewController textFiledTest]_block_invoke241 + 211 x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '123123'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0>; layer = 0x7fe810c51600>>
__31-[ViewController textFiledTest]_block_invoke_2 + 215 x = 123123

我们很容易的监听到textFiled中发生的变化,其中x的类型默认为id类型,我们已知它的类型的时候我们可以将其改变,就像上面代码,将id改成NSString类型。

手势

self.view.userInteractionEnabled = YES;
    UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]init];
    [[tap rac_gestureSignal] subscribeNext:^(UITapGestureRecognizer * tap) {
        
        LxDBAnyVar(tap);
    }];
    [self.view addGestureRecognizer:tap];

为了方便,我们直接添加到self.view上,点击屏幕,得到打印结果:

__29-[ViewController gestureTest]_block_invoke + 184 tap = 0x7fa2e3e1f9f0; state = Ended; view = 0x7fa2e3e20b70>; target= action=sendNext:, target=0x7fa2e3c064f0>)>>

通知

[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil] subscribeNext:^(NSNotification * notification) {
       
       LxDBAnyVar(notification);
   }];

我们建立了一个通知,叫做进入后台,当程序进入后台的时候通知相应,当我们用RAC写通知的时候,我们有一个好处,就是不用removeObserve通知,因为RAC通知的监听者是RAC自己,它会帮你管理释放方法。可以看方法实现如下:

- (RACSignal *)rac_addObserverForName:(NSString *)notificationName object:(id)object {
    @unsafeify(object);
    return [[RACSignal createSignal:^(idRACSubscriber> subscriber) {
        @strongify(object);
        id observer = [self addObserverForName:notificationName object:object queue:nil usingBlock:^(NSNotification *note) {
            [subscriber sendNext:note];
        }];

        return [RACDisposable disposableWithBlock:^{
            [self removeObserver:observer];
        }];
    }] setNameWithFormat:@"-rac_addObserverForName: %@ object: ", notificationName, [object class], object];
}

定时器

//1. 延迟某个时间后再做某件事
[[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
    
    LxPrintAnything(rac);
}];

//2. 每间隔多长时间做一件事
[[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]subscribeNext:^(NSDate * date) {
    
    LxDBAnyVar(date);
}];

这是定时器最常用的两种写法,第一种方法,延迟时间去做某件事情,更改afterDelay的属性。
第二种方法,每间隔多长时间做一件事情,更改interval属性。

代理

UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"RAC" message:@"ReactiveCocoa" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ensure", nil];
   
   [[self rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)] subscribeNext:^(RACTuple * tuple) {
       
       LxDBAnyVar(tuple);
       
       LxDBAnyVar(tuple.first);
       LxDBAnyVar(tuple.second);
       LxDBAnyVar(tuple.third);
   }];
   [alertView show];
   
   
   //   更简单的方式:
   [[alertView rac_buttonClickedSignal]subscribeNext:^(id x) {
       
       LxDBAnyVar(x);
   }];

用RAC去写代理的时候,会有局限,只能取代没有返回值的代理方法,什么是没有返回值的代理呢?比如说tableView的代理方法:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

你可能感兴趣的:(ReactiveCocoa(RAC)框架)