iOS-ReactiveCocoa简介

作者: FlyElephant | 来源:发表于2017-05-01 18:32 被阅读1786次

ReactiveCocoa(RAC(是一个在KVO的基础上建立Objective-C的框架,函数式响应式框架,提供了组合和转化数据流的API.将iOS中的Action、Delegate、Target、KVO、Block,NSNotification统一共同的消息传递机制进行事件处理,属性变化,回调响应.

ReactiveCocoa为事件定义了一个标准接口,从而可以使用一些基本工具来更容易的连接、过滤和组合.RACSignal作为事件源,会给它的订阅者(subscribers)发送一连串的事件.Signal有三种事件:next,error和completed,可以在error或completed事件发出前发出任意多的next事件.

RAC为UIKit添加了很多类别来让我们可以订阅UI组件的事件,比如UITextField (RACSignalSupport)中的rac_textSignal会在文本域内容变化时发出next事件,事件包含的内容需要是对象类型,如果是数字类型,布尔值等字面量,可以用 @() 语法装箱成NSNumber对象.ReactiveCocoa对常用的UI控件进行了扩展,如图所示:


FlyElephant.png

消息事件

RAC信号作为传递信号的工具,当数据变化时,信号就会发送改变的信息,以通知信号的订阅者执行方法.默认信号都是冷信号,也就是值改变了,也不会触发,只有订阅了这个信号,这个信号才会变为热信号,值改变了才会触发.

KVO

定义课程Course类,定义如下:
<pre><code>`@interface Course : NSObject

@property (copy, nonatomic) NSString *courseName;

@property (assign, nonatomic) NSInteger courseType;

@end`</code></pre>

CourseName与CourseLabel绑定:
<pre><code>` @weakify(self)

[RACObserve(self.course, courseName)
 subscribeNext:^(id x) {
     @strongify(self)
     NSLog(@"键值对变化--%@",x);
     self.nameLabel.text = x;
 }];`</code></pre>

按钮点击的时候改变课程名字:
<pre><code>- (IBAction)courseAction:(UIButton *)sender { self.course.courseName = [NSString stringWithFormat:@"FlyElephant--%d",arc4random_uniform(25)]; }</code></pre>

UITextField 事件监听

<pre><code>@weakify(self) [self.textField.rac_textSignal subscribeNext:^(id x) { @strongify(self) NSLog(@"TextField变化--%@",x); self.course.courseName = x; }];</code></pre>

FlyElephant.gif
信号绑定

信号绑定最常见的常见就是注册过程用户名和密码如果都有数据按钮可以点击,否则就不可以点击:
<pre><code>` id textFieldSignals = @[self.textField.rac_textSignal,self.passWordTextField.rac_textSignal];

@weakify(self);

[[RACSignal combineLatest:textFieldSignals] subscribeNext:^(RACTuple *x) {
    @strongify(self);
    
    NSString *name = [x first];
    NSString *passWord = [x second];
    
    if (name.length && passWord.length) {
        self.loginButton.backgroundColor = [UIColor redColor];
        self.loginButton.userInteractionEnabled = YES;
    } else {
        self.loginButton.backgroundColor = [UIColor darkGrayColor];
        self.loginButton.userInteractionEnabled = NO;
    }
}];

`</code></pre>

FlyElephant.gif
UIButton按钮事件

<pre><code>@weakify(self); [[self.loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { @strongify(self); NSLog(@"用户名:--%@---密码:%@",self.textField.text,self.passWordTextField.text); }];</code></pre>

Delegate事件

RAC中通过RACDelegateProxy实现Delegate,但是有一点需要在类中声明Delegate变量,避免提前释放:
<pre><code>@weakify(self); self.textDelegate = [[RACDelegateProxy alloc] initWithProtocol:@protocol(UITextFieldDelegate)]; [[self.textDelegate rac_signalForSelector:@selector(textFieldShouldReturn:)] subscribeNext:^(id x) { @strongify(self); NSLog(@"FlyElephant---代理执行"); [self.passWordTextField becomeFirstResponder]; }]; self.textField.delegate = (id<UITextFieldDelegate>)self.textDelegate;</code></pre>

NSNotification通知事件

NSNotification事件执行之后可以传递给next进行事件处理:
<pre><code>[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) { NSLog(@"键盘弹出事件"); }];</code></pre>

信号处理

RACSignal中很多方法用于订阅事件,每个方法都会将类型为(void (^)(id x))的block作为参数,当事件发生时block中的代码会执行,例如 subscribeNext: 方法会传入一个block作为参数,当Signal的next事件发出后,block会接收到事件并执行.

RACSignal还有一些方法是对Signal做操作的, 在RACSignal (Operations)类别还有其他的方式,map,filter,throttle....

创建信号

<pre><code>` RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"FlyElephant"];
[subscriber sendCompleted];
return nil;
}];

//订阅信号
[signal subscribeNext:^(id x) {
    NSLog(@"信号值 = %@", x);
} error:^(NSError *error) {
    NSLog(@"error = %@", error);
} completed:^{
    NSLog(@"completed");
}];`</code></pre>
Map

<pre><code>[[self.textField.rac_textSignal map:^id(NSString *value) { return @(value.length); }] subscribeNext:^(id x) { NSLog(@"信号量Map:%@",x); }];</code></pre>

Filter

<pre><code>[[self.textField.rac_textSignal filter:^BOOL(NSString *value) { return [value length] > 5; }] subscribeNext:^(id x) { NSLog(@"value字符串变换 = %@", x); }];</code></pre>

Take/Skip

<pre><code>` RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@"2"];
[subscriber sendNext:@"3"];
[subscriber sendNext:@"4"];
[subscriber sendNext:@"5"];
[subscriber sendCompleted];
return nil;
}];

RACSignal *takeSignal = [signal take:2];
[takeSignal subscribeNext:^(id x) {
    NSLog(@"Take---%@", x);
} completed:^{
    NSLog(@"Take---FlyElephant---completed");
}];

RACSignal *skipSignal = [signal skip:2];
[skipSignal subscribeNext:^(id x) {
    NSLog(@"Skip---%@", x);
} completed:^{
    NSLog(@"Skip---completed");
}];`</code></pre>
Delay

<pre><code>` RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"FlyElephant"];
[subscriber sendCompleted];
return nil;
}] delay:2];

NSLog(@"FlyElephant-delay");

[signal subscribeNext:^(id x) {
    NSLog(@"%@", x);
}];`</code></pre>
throttle

在做搜索框的时候,有时需要实时搜索,即用户每每输入字符,view都要求展现搜索结果.这时如果用户搜索的字符串较长,那么由于网络请求的延时可能造成UI显示错误,并且多次不必要的请求还会加大服务器的压力,这显然是不合理的,此时我们就需要用到节流.
<pre><code>[[self.textField.rac_textSignal throttle:0.5] subscribeNext:^(id x) { NSLog(@"Throttle---%@", x); }];</code></pre>

distinctUntilChanged

网络请求中为了减轻服务器压力,无用的请求我们应该尽可能不发送,distinctUntilChanged的作用是使RAC不会连续发送两次相同的信号.
<pre><code>[[self.textField.rac_textSignal distinctUntilChanged] subscribeNext:^(id x) { NSLog(@"FlyElephant---防止重复请求:%@",x); }];</code></pre>

timeOut

<pre><code>` RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[[RACScheduler mainThreadScheduler] afterDelay:3 schedule:^{
[subscriber sendNext:@"FlyElephant--TimeOut"];
[subscriber sendCompleted];
}];
return nil;
}] timeout:2 onScheduler:[RACScheduler mainThreadScheduler]];

[signal subscribeNext:^(id x) {
    NSLog(@"TimeOut---%@", x);
} error:^(NSError *error) {
    NSLog(@"TimeOut---%@", error);
}];`</code></pre>
ignore

<pre><code>[[self.textField.rac_textSignal ignore:@"FlyElephant"] subscribeNext:^(id x) { NSLog(@"ignore---%@", x); }];</code></pre>

ReactiveCocoa实际使用过程中还有无数种演绎用法,本文只是介绍其中的九牛一毛,如果有写的不恰当的地方,欢迎指正~

相关文章

  • iOS-ReactiveCocoa简介

    ReactiveCocoa(RAC(是一个在KVO的基础上建立Objective-C的框架,函数式响应式框架,提供...

  • iOS-ReactiveCocoa

    什么是ReactiveCocoa? ReactiveCocoa(其简称为RAC)是由Github 开源的一个应用于...

  • iOS-ReactiveCocoa相关

    第一传送门基础教程 第二传送门基础篇 第二传送门进阶篇 第三传送门官方文档翻译 注意点: RAC 使用的时候,回调...

  • iOS-ReactiveCocoa学习笔记

    关于ReactiveCocoa的比喻 “能够把信号想象成水龙头,仅仅只是里面不是水,而是玻璃球(value),直径...

  • iOS-ReactiveCocoa使用之RACCommand

    前言 前几天开始研究Cocoa的第三方编程框架ReactiveCocoa,其使用响应式、函数式的编程思想,对于初识...

  • iOS-ReactiveCocoa学习笔记1

    一篇关于RectiveCocoa的总结文档 百度搜索了一下RectiveCocoa,都是与MVVM关联在一起。 1...

  • iOS-ReactiveCocoa 响应式编程框架学习推荐博客

    首先强烈推荐一个简书作者 SkyHarute,他的简书里面有一个 ReactiveCocoa 专栏,都是非常实用的...

  • 18旅游二班各组自我简介汇总

    一组简介 二组简介 三组简介 四组简介 五组简介 六组简介 七组简介 八组简介

  • 简介

    上辈子,洛幽喜欢了东凡一辈子,没有结果,之后她死了,她不后悔,只是为什么她一睁眼,嗯?捏了捏自己的脸,她这是回到了...

  • 简介

    1.主动地去阅读。 2.阅读目的:获得资讯,获得理解 前者为了增进资讯,获得信息,不能增加理解力。后者为了理解更多...

网友评论

    本文标题:iOS-ReactiveCocoa简介

    本文链接:https://www.haomeiwen.com/subject/pjiftxtx.html