ReactiveCocoa学习(1)

ReactiveCocoa介绍

ReactiveCocoa(RAC)是一个在KVO的基础上建立Objective-C的框架,用于函数式反应型编程,它提供了组合和转化数据流的API。

它提供统一的消息传递机制,不再使用之前的比如action、delegate、target、KVO、callback等方式来处理以下事件比如按钮的点击,收到网络消息,属性的变化(通过KVO)或者用户位置的变化。

ReactiveCocoa为事件定义了一个标准接口,从而可以使用一些基本工具来更容易的连接、过滤和组合。

RAC的核心是Signal,对应的类为RACSignal,它其实是一个事件源,Signal会给它的订阅者(subscribers)发送一连串的事件。有三种事件:next,error和completed。Signal可以在error或completed事件发出前发出任意多的next事件。

RAC为UIKit添加了很多类别来让我们可以订阅UI组件的事件,比如UITextField (RACSignalSupport)中的rac_textSignal会在文本域内容变化时发出next事件,事件包含的内容可以是类型,只要是对象就行,如果是一些数字,布尔值等字面量,可以用 @() 语法装箱成NSNumber。只要控件中有响应的在RAC中都有Extension,比如UIGestureRecognizer,UIAlertView不用delegate就可以知道点击哪个按钮等

ReactiveCocoa结合了几种编程风格:

函数式编程(Functional Programming):使用高阶函数,例如函数用其他函数作为参数。

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

ReactiveCocoa的使用

这次是在项目中使用的cocosPod方式,这种感觉简单,如果想直接导入ReactiveCocoa,详见官网。

在Podfile中加入下面一句话

pod'ReactiveCocoa'

RAC中的类和方法

RACSignal是RACStream的子类。

RACStream

RACStream是一个抽象类,描述了值的流动,列举一下它比较常用的操作(Operations类别):

- filter: 对RACStream中的事件内容进行过滤,返回一个过滤事件内容后的instancetype

- map: 会将事件中的数据转换成你想要的数据,返回一个转换事件内容后的instancetype

- flattenMap: 在map的基础上使其flatten,也就是当Signal嵌套(一个Signal的事件是另一个Signal)的时候,会将内部Signal的事件传递给外部Signal

- distinctUntilChanged 比较数值流中当前值和上一个值,如果不同,就返回当前值,简单理解为“流”的值有变化时反馈变化的值,求异存同。

- PS:instancetype是程序运行时对象的类型,有可能为RACStream,也可以为其子类RACSignal。正是因为这些操作事件的方法都会返回事件源对象相同的类型,事件可以被一连串的被这些方法修改,过滤等,这就形成了管道,管道中传递着事件,包含着value。

RACSignal

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

RACSignal还有一些方法是对Signal做操作的, 在RACSignal (Operations)类别中有详细的描述,比较常用的如下:

- combineLatest:reduce: 将一组Signal发出的最新的事件合并成一个Signal,每当这组Signal发出新事件时,reduce的block会执行,将所有新事件的值合并成一个值,并当做合并后Signal的事件发出去。这个方法会返回合并后的Signal。

PS:关于reduce的block中参数,其实是与combineLatest中数组元素一一对应的,这里RAC用了一个黑魔法,参看 RACBlockTrampoline

- doNext: 这个向Signal管道上添加添加副作用。它并不会改变事件,参数block也没有返回值,它返回一个执行了block的Signal,这样block中的副作用就被注入到了以前的Signal。

- then: 当一个订阅者被发送了completed事件后, then: 方法才会执行,订阅者会订阅 then: 方法返回的Signal,这个Signal是在block中返回的。这样优雅的实现了从一个Signal到另一个Signal的订阅。

- deliverOn: 参数为RACScheduler类的对象scheduler,这个方法会返回一个Signal,它的所有事件都会传递给scheduler参数所表示的线程,而以前管道上的副作用还会在以前的线程上。这个方法主要是切换线程。

- subscribeOn: 功能跟 deliverOn: 相同,但是它也会将副作用也切换到制定线程中。

- throttle: 它接收一个时间间隔interval作为参数,如果Signal发出的next事件之后interval时间内不再发出next事件,那么它返回的Signal会将这个next事件发出。也就是说,这个方法会将发送比较频繁的next事件舍弃,只保留一段“静默”时间之前的那个next事件,这个方法常用于处理输入框等信号(用户打字很快),因为它只保留用户最后输入的文字并返回一个新的Signal,将最后的文字作为next事件参数发出。

and 、 or 、 not NSNumber中Bool的与、或、非操作,将Signal发出的事件内容转化。

还可以根据方法(SEL类型)来创建Signal,每当该方法被调用时,Signal都会将此方法被传入的参数打包成 RACTuple 元组类型来发送next事件给它的接受者。 rac_signalForSelector: 和 rac_signalForSelector:fromProtocol: 这两个方法都能通过指定的方法来创建Signal。

RACSubscriber

RACSubscriber是一个协议,包含了向订阅者发送事件的方法。

[RACSignal createSignal:^RACDisposable *(idsubscriber) {

[subscriber sendNext:@(YES)];

[subscriber sendCompleted];

returnnil;

}];

上面方法用于创建一个Signal,当Signal被订阅时, createSignal: 的参数block中的内容被执行。block的参数是一个实现RACSubscriber协议的对象,然后向这个订阅者发送了next事件(内容为NSNumber类型的@YES值)和completed事件。

PS:除此之外RACSubscriber还有 sendError: 和 didSubscribeWithDisposable: 两个方法。

RACDisposable

RACSignal (Subscription)类别中所有方法的返回值类型都是RACDisposable,它的 dispose 方法可以让我们手动移除订阅者。

例如:

RACSignal *backgroundColorSignal =  [self.searchText.rac_textSignal    map:^id(NSString *text) {return[self isValidSearchText:text] ?        [UIColor whiteColor] : [UIColor yellowColor];    }]; RACDisposable *subscription =  [backgroundColorSignal    subscribeNext:^(UIColor *color) {      self.searchText.backgroundColor = color;    }]; // at some pointinthe future...[subscription dispose];

1

注:当管道的订阅者全部被移除后,管道中的代码不会执行,包括三种事件参数block中的代码和诸如 doNext: 等副作用的block。可以简单理解为,当管道中的Signal没人订阅,它的事件就不会发出了。

RACCommand

RACCommand 通常用来表示某个Action的执行,比如点击Button。

RACScheduler

类似于GCD中的序列,是管理线程的类,负责RAC中让信号发出的事件华丽丽的在线程中穿梭,尤其是想更新UI必须在主线程中的时候,可以让事件直接从其他线程跳到主线程。此外RACScheduler也有优先级、延时等GCD中的特性。

解决引用循环

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容

  • RAC使用测试Demo下载:github.com/FuWees/WPRACTestDemo 1.ReactiveC...
    FuWees阅读 6,368评论 3 10
  • 1.ReactiveCocoa常见操作方法介绍。 1.1 ReactiveCocoa操作须知 所有的信号(RACS...
    萌芽的冬天阅读 1,021评论 0 5
  • 前言由于时间的问题,暂且只更新这么多了,后续还会持续更新本文《最快让你上手ReactiveCocoa之进阶篇》,目...
    Karos_凯阅读 1,736评论 0 6
  • 作为一个iOS开发者,你写的每一行代码几乎都是在相应某个事件,例如按钮的点击,收到网络消息,属性的变化(通过KVO...
    jiajia1118阅读 799评论 0 2
  • 村里唱戏,妈妈昨天就打电话让回去。可是下午雨挺大,就没有出门。 今天回去,路过老房子,几乎要被杂草包围,尤其是门口...
    素衣烟霞阅读 136评论 0 0