由于工作原因,有段时间没更新博客了,甚是抱歉,只是,从今天開始我又活跃起来了,哈哈,于是决定每周更新一博。大家互相学习。交流。

今天呢。讨论一下关于ReactiveCocoa,这个採用函数响应式编程(FRP)的框架,下面会对ReactiveCocoa简称为RAC。

之前看过一遍文章,说的是作为一个iOS开发人员,写的每一行代码差点儿都是在对应某个事件,比如button的点击。收到网络消息,属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation)。可是这些事件都用不同的方式来处理,比方action、delegate、KVO、callback等。

我非常赞同这种说法,于是。即然这种话,那我们为什么不把这些须要响应的事件流统一放在一起呢。非常幸运的是,Github有一个开源项目,即 ReactiveCocoa简称RAC,就是基于响应式编程思想的Objective-C实践。

何为RAC呢:RAC是为应用中发生的不同事件流提供了一个标准接口。我们能够使用一些基本工具来更easy的连接、过滤和组合。

RAC结合了几种编程风格:

函数式编程(Functional Programming):使用高阶函数。比如函数用其它函数作为參数。

响应式编程(Reactive Programming):关注于数据流和变化传播。

所以,你可能听说过ReactiveCocoa被描写叙述为函数响应式编程(FRP)框架。

有句比喻非常好非常形象的对RAC做了总结:

“能够把信号想象成水龙头,仅仅只是里面不是水,而是玻璃球(value),直径跟水管的内径一样,这样就能保证玻璃球是依次排列。不会出现并排的情况(数据都是线性处理的,不会出现并发情况)。水龙头的开关默认是关的。除非有了接收方(subscriber),才会打开。

这样仅仅要有新的玻璃球进来,就会自己主动传送给接收方。

能够在水龙头上加一个过滤嘴(filter)。不符合的不让通过,也能够加一个修改装置,把球改变成符合自己的需求(map)。

也能够把多个水龙头合并成一个新的水龙头(combineLatest:reduce:),这样仅仅要当中的一个水龙头有玻璃球出来,这个新合并的水龙头就会得到这个球。


--  来自博文 http://blog.csdn.net/xdrt81y/article/details/30624469



  首先导入RAC框架:

    能够通过CocoaPods导入RAC框架:

platform:ios,'9.0'

use_frameworks! #导入才不会报错

pod'ReactiveCocoa'

  RAC为应用中发生的不同事件流提供了一个标准接口。

在ReactiveCocoa术语中这个叫做信号(signal),由RACSignal类表示。

ReactiveCocoa
signal(RACSignal)发送事件流给它的subscriber(订阅者)。

眼下总共同拥有三种类型的事件:next、error、completed。一个signal在因error终止或者完毕前,能够发送随意数量的next事件。RACSignal有非常多方法能够来订阅不同的事件类型。每一个方法都须要至少一个block。当事件发生时就会运行block中的逻辑。

  ReactiveCocoa框架使用category来为非常多基本UIKit控件加入signal。这样就能给控件加入订阅了,text
field的rac_textSignal就是这么来的。

  看个样例:

RACSignal *usernameSourceSignal =self.usernameTextField.rac_textSignal;

RACSignal *filteredUsername = [usernameSourceSignalfilter:^BOOL(id
value) {

NSString *string = value;

return string.length >3; 
 }];

[filteredUsernamesubscribeNext:^(id x) {

NSLog(@"%@",x);  }];

在这里。rac_textSignal是起始事件。然后数据通过一个filter。假设这个事件包括一个长度超过3的字符串,那么该事件就能够通过。

管道的最后一步就
 是subscribeNext:,block在这里打印出事件的值。

filter操作的输出也是RACSignal。

   事实上。RACSignal的每一个操作都会返回一个RACsignal,这在术语上叫做连贯接口(fluent
interface)。这个功能能够让你直接构建管道。而不用每一步都使用本地变量。

  于是将上面的样例。能够变成:

      [[self.usernameTextField.rac_textSignalfilter:^BOOL(NSString*
string) {

return  string.length >3 ;

}]subscribeNext:^(id x) {

NSLog(@"*** %@",x);

}];

类型转换:

我们能够使用map(转换)操作通过block改变事件的数据。

map从上一个next事件接收数据。通过运行block把返回值传给下一个next事件。在上面的代码中,map以NSString为输入,取字符串的长度,返回一个NSNumber。

举个栗子:

[[[self.usernameTextField.rac_textSignalmap:^id(NSString
*text) {

return@(text.length);

}]filter:^BOOL(NSNumber *length
) {

return  [lengthintegerValue];

}]subscribeNext:^(id x) {

NSLog(@"map___%@",x);

}];

能看到map操作之后的步骤收到的都是NSNumber实例。你能够使用map操作来把接收的数据转换成想要的类型。仅仅要它是个对象。



创建有效状态信号:

     首先要做的就是创建一些信号,比方常见的登录界面,来表示username和password输入框中的输入内容是否有效,如:

RACSignal *validUsernameSignal = [self.usernameTextField.rac_textSignalmap:^id(NSString
*text) {

return@([selfisValidUsername:text]);

}];

RACSignal *validPasswordSignal = [self.passwordTextField.rac_textSignalmap:^id(id
value) {

NSString *text = value;

return@([selfisValidPassword:text]);

}];



我们能够转换这些信号,从而能为输入框设置不同的背景颜色。

基本上就是,你订阅这些信号,然后用接收到的值来更新输入框的背景颜色。

使用RAC宏

RAC宏同意直接把信号的输出应用到对象的属性上。

RAC宏有两个參数,第一个是须要设置属性值的对象,第二个是属性名。

每次信号产生一个next事件,传递过来的值都会应用到该属性上。

RAC(self.passwordTextField,backgroundColor) = [validPasswordSignalmap:^id(NSNumber
*passwordValid) {

NSLog(@"%d",[passwordValidboolValue]);

return [passwordValidboolValue]?[UIColorclearColor]:[UIColoryellowColor];

}];

RAC(self.usernameTextField,backgroundColor) = [validUsernameSignalmap:^id(NSNumber
*usernameValid) {

NSLog(@"%d",[usernameValidboolValue]);

return [usernameValidboolValue]?[UIColorclearColor]:[UIColoryellowColor];

}];

信号聚合

使用combineLatest:reduce:方法把几个信号RACSignal产生的最新的值聚合在一起,并生成一个新的信号。

每次这两个源信号的不论什么一个产生新值时。reduce
block都会运行,block的返回值会发给下一个信号。

RACSignal *signUpActiveSignal = [RACSignalcombineLatest:@[validUsernameSignal,validPasswordSignal]reduce:^id(NSNumber
*usernameValid,NSNumber *passwordValid){

return@([usernameValidboolValue]&&[passwordValidboolValue]);

}];

[signUpActiveSignalsubscribeNext:^(NSNumber *signupActive) {

self.signInButton.enabled
= [signupActiveboolValue];

}];

ReactiveCocoa处理button的事件

须要用到ReactiveCocoa为UIKit加入的还有一个方法,rac_signalForControlEvents。

信号中的信号

使用map方法,把button点击信号转换成了登录信号。

subscriber输出log,把map操作改成flattenMap,这个操作把button点击事件转换为登录信号,同一时候还从内部信号发送事件到外部信号。

doNext:是直接跟在button点击事件的后面。并且doNext: block并没有返回值。

由于它是附加操作,并不改变事件本身。

[[[[self.signInButton

rac_signalForControlEvents:UIControlEventTouchUpInside]

doNext:^(id x){

self.signInButton.enabled
=NO;

self.signInFailureText.hidden
=YES;

}]

flattenMap:^id(id x){

return[selfsignInSignal];

}]

subscribeNext:^(NSNumber*signedIn){

self.signInButton.enabled
=YES;

BOOL success =[signedInboolValue];

self.signInFailureText.hidden
= success;

if(success){

[selfperformSegueWithIdentifier:@"signInSuccess"sender:self];

}

}];



创建信号

     使用RACSignal的createSignal:方法来创建信号。

方法的參数是一个block,这个block描写叙述了这个信号。当这个信号有subscriber时。block里的代码就会运行。

block的參数是一个subscriber实例,它遵循RACSubscriber协议。协议里有一些方法来产生事件,你能够发送随意数量的next事件,或者用error\complete事件来终止。本例中,信号发送了一个next事件来表示登录是否成功。随后是一个complete事件。

这个block的返回值是一个RACDisposable对象。它同意你在一个订阅被取消时运行一些清理工作。当前的信号不须要运行清理操作,所以返回nil就能够了。

- (RACSignal *)signInSignal {

return [RACSignalcreateSignal:^RACDisposable
*(id subscriber){

[self.signInService

signInWithUsername:self.usernameTextField.text

password:self.passwordTextField.text

complete:^(BOOL success){

[subscribersendNext:@(success)];

[subscribersendCompleted];

}];

returnnil;

}];

}

总结:

ReactiveCocoa的核心就是信号,而它只是就是事件流,ReactiveCocoa的主旨是让你的代码更简洁易懂。这值得多想想。



这里将附上demo。欢迎大家阅读。

















函数响应式编程(FRP)框架--ReactiveCocoa的更多相关文章

  1. 函数响应式编程(FRP)—基础概念篇

    原文出处:http://ios.jobbole.com/86815/. 一函数响应式编程 说到函数响应式编程,就不得不提到函数式编程,他们俩有什么关系呢?今天我们就详细的解析一下他们的关系. 现在下面 ...

  2. 函数响应式编程(FRP)从入门到”放弃”——基础概念篇

    前言 研究ReactiveCocoa一段时间了,是时候总结一下学到的一些知识了. 一.函数响应式编程 说道函数响应式编程,就不得不提到函数式编程,它们俩到底有什么关系呢?今天我们就详细的解析一下他们的 ...

  3. 函数响应式编程(FRP)思想-Callback风格

    序 ReactiveCocoa是IOS广为使用的技术框架,而ReactiveCocoa的核心思想就FRP.FRP不同于JAVA的object-oriented和AOP,FRP能让你的代码像数学一样简洁 ...

  4. ReactiveCocoa,最受欢迎的iOS函数响应式编程库(2.5版),没有之一!

    简介 项目主页: ReactiveCocoa 实例下载: https://github.com/ios122/ios122 简评: 最受欢迎,最有价值的iOS响应式编程库,没有之一!iOS MVVM模 ...

  5. 函数响应式编程及ReactiveObjC学习笔记 (-)

    最近无意间看到一个视频讲的ReactiveObjC, 觉得挺好用的 但听完后只是了解个大概. 在网上找了些文章, 有的写的比较易懂但看完还是没觉得自己能比较好的使用RAC, 有的甚至让我看不下去 这两 ...

  6. RxJS入门之函数响应式编程

    一.函数式编程 1.声明式(Declarativ) 和声明式相对应的编程⽅式叫做命令式编程(ImperativeProgramming),命令式编程也是最常见的⼀种编程⽅式. //命令式编程: fun ...

  7. RxSwift 函数响应式编程

    Max 在 Boston 上学,在 San Francisco 工作,是一名软件工程师及创业者.当他还在高中的时候就在一家创业公司工作了,他非常喜欢使用 iOS.Android 以及 JavaScri ...

  8. 函数响应式编程RxJava

    RxJava 到底是什么 一个词:异步. RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event- ...

  9. 函数响应式编程及ReactiveObjC学习笔记 (二)

    之前我们初步认识了RAC的设计思路跟实现方式, 现在我们再来看看如果使用它以及它能帮我们做什么 One of the major advantages of RAC is that it provid ...

随机推荐

  1. Tasker : Scale Up/Down CPU Speed at Different Times

    http://techsplurge.com/4926/android-awesome-15-tasker-profiles-tutorials/ Yeah I know, there’s SetCP ...

  2. .Net高级技术——对象序列化

    对象序列化 “序列化是将一个对象保存到存储介质上或者将对象进行转换使之能够在网络上传送的行为”.通俗一点的解释,序列化就是把一个对象保存到一个文件或数据库字段中去,反序列化就是从文件或者数据库中取出数 ...

  3. C++回调函数(callback)的使用

    什么是回调函数(callback)    模块A有一个函数foo,他向模块B传递foo的地址,然后在B里面发生某种事件(event)时,通过从A里面传递过来的foo的地址调用foo,通知A发生了什么事 ...

  4. MVC扩展Filter, 通过继承AuthorizationAttribute限制IP

    为什么需要AuthorizationAttribute 在没有Authorization系统属性之前,我们可能这样判断:Request.IsAuthenticated && User. ...

  5. Spring MVC的异步模式DefferedResult

    原文:http://www.importnew.com/21051.html 什么是异步模式 要知道什么是异步模式,就先要知道什么是同步模式,先看最典型的同步模式: (图1) 浏览器发起请求,Web服 ...

  6. Entityframework:启用延时加载的主意事项(只为强化记忆)

    Check List 无参的.高于私有访问级别的构造方法(经常忘记). 非封闭的类(默认的非封闭的). DbContext 配置要开启(默认是开启的). 因为我喜欢将类型设置为封闭的,提供有参数的构造 ...

  7. Python3.6学习笔记(三)

    面向对象编程 面向对象编程 Object Oriented Programming 简称 OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程 ...

  8. 安装在virtualbox中的kali linux如何配置无线网卡

    1.安装在virtualbox里的kali无法使用所在物理机的wifi 2.必须通过usb方式,如图所示 3.所使用的usb无线网卡必须是kali2.0支持的 4.我的型号是TL-WN823N 2.0 ...

  9. Objective-C:随机的读取文件中的内容

    可以通过改变当前文件的偏移量来实现文件的读取 -offsetInFile获取文件当前的位移量 -seekToFileOffset:(NSUInteger)length设置文件当前的位移量 -readD ...

  10. C#的几种写文件方法

    C#写文件处理操作在很多的开发项目中都会涉及,那么具体的实现方法是什么呢?这里向大家介绍三大方法,希望对你在开发应用中有所启发. 首先C#写文件处理操作必须先导入命名空间:using System.I ...