An abstract class representing any stream of values.编程
RACStream
是一个抽象类,是以 Monad
(函数式编程语言)的概念为依据进行设计的,它表明的就是一个 Monad
。有了 Monad
做为基石后,许多基于流的操做就能够被创建起来了,好比map
、 filter
、 zip
等。缓存
能够把信号想象成水龙头,只不过里面不是水,而是玻璃球(value),直径跟水管的内径同样,这样就能保证玻璃球是依次排列,不会出现并排的状况(数据都是线性处理的,不会出现并发状况)。水龙头的开关默认是关的,除非有了接收方(subscriber),才会打开。这样只要有新的玻璃球进来,就会自动传送给接收方。能够在水龙头上加一个过滤嘴(filter),不符合的不让经过,也能够加一个改动装置,把球改变成符合本身的需求(map)。也能够把多个水龙头合并成一个新的水龙头(combineLatest:reduce:),这样只要其中的一个水龙头有玻璃球出来,这个新合并的水龙头就会获得这个球。闭包
RACSignal
表明的是未来会被传递的值,它是一种 push-driven
的流。 RACSignal
能够向订阅者发送三种不一样类型的事件:并发
next
: RACSignal
经过 next
事件向订阅者传送新的值,而且这个值能够为 nil
;error
: RACSignal
经过 error
事件向订阅者代表信号在正常结束前发生了错误;completed
: RACSignal
经过 completed
事件向订阅者代表信号已经正常结束,不会再有后续的值传送给订阅者。注意, ReactiveCocoa
中的值流只包含正常的值,即经过 next
事件传送的值,并不包括 error
和 completed
事件,它们须要被特殊处理。一般状况下,一个信号的生命周期是由任意个next
事件和一个 error
事件或一个 completed
事件组成的。less
RACSignal
的 Subscription
过程归纳起来能够分为三个步骤:编程语言
RACSubject
表明的是能够手动控制的信号,咱们能够把它看做是 RACSignal
的可变版本,就比如 NSMutableArray
是 NSArray
的可变版本同样。 RACSubject
继承自 RACSignal
,因此它能够做为信号源被订阅者订阅,同时,它又实现了 RACSubscriber
协议,因此它也能够做为订阅者订阅其余信号源,这个就是 RACSubject
为何能够手动控制的缘由。ide
实际使用中,在 MVVM
中使用 RACSubject
能够很是方便地实现统一的错误处理逻辑。好比,咱们能够在 viewModel
的基类中声明一个 RACSubject
类型的属性 errors
,而后在 viewController
的基类中编写统一的错误处理逻辑:函数式编程
[self.viewModel.errors subscribeNext:^(NSError *error) {
// 错误处理逻辑
}
A command is a signal triggered in response to some action, typically UI-related.函数
RACCommand
一般用来表示某个 Action
的执行,好比点击 Button
。它有几个比较重要的属性:executionSignals / errors / executing。oop
executionSignals
:是 signal of signals ,若是直接 subscribe 的话会获得一个 signal ,而不是咱们想要的 value,因此通常会配合 switchToLatest
。errors
:跟正常的 signal 不同,RACCommand 的错误不是经过 sendError 来实现的,而是经过 errors 属性传递出来的。executing
:表示该 command 当前是否正在执行。Represents an immutable sequence of values. Unless otherwise specified, the sequences’ values are evaluated lazily on demand. Like Cocoa collections, sequences cannot contain nil.
RACSequence
表明的是一个不可变的值的序列,与 RACSignal
不一样,它是 pull-driven
类型的流。从严格意义上讲, RACSequence
并不能算做是信号源,由于它并不能像 RACSignal
那样,能够被订阅者订阅,可是它与 RACSignal
之间能够很是方便地进行转换。
所以,咱们能够很是方便地使用 RACSequence
来实现集合的链式操做,直到获得你想要的最终结果为止,经常使用的使用场景为「字典转模型」。
注意: RACSequence
会涉及到性能与效率的问题。
Represents any object which can directly receive values from a RACSignal.
订阅者对信号源的一次订阅过程能够抽象为:经过 RACSignal
的 -subscribe:
方法传入一个订阅者,并最终返回一个 RACDisposable
对象的过程。
注意:在 ReactiveCocoa
中并无专门的类 RACSubscription
来表明一次订阅,而间接地使用 RACDisposable
来充当这一角色。所以,一个 RACDisposable
对象就表明着一次订阅,而且咱们能够用它来取消此次订阅。
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock { trueNSCParameterAssert(nextBlock != NULL); true trueRACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL]; truereturn [self subscribe:o]; } + (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed { trueRACSubscriber *subscriber = [[self alloc] init]; truesubscriber->_next = [next copy]; truesubscriber->_error = [error copy]; truesubscriber->_completed = [completed copy]; truereturn subscriber; } - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber { trueNSCAssert(NO, @"This method must be overridden by subclasses"); truereturn nil; }
Schedulers are used to control when and where work is performed.
RACScheduler
在 ReactiveCocoa
中就是扮演着调度器的角色,本质上,它就是用 GCD
的串行队列来实现的,而且支持取消操做。是的,在 ReactiveCocoa
中,并无使用到 NSOperationQueue
和 NSRunloop
等技术, RACScheduler
也只是对 GCD
的简单封装而已。
A disposable encapsulates the work necessary to tear down and cleanup a subscription.
RACDisposable
在 ReactiveCocoa
中就充当着清洁工的角色,它封装了取消和清理一次订阅所必需的工做。它有一个核心的方法 -dispose
,调用这个方法就会执行相应的清理工做,这有点相似于 NSObject
的 -dealloc
方法。
rac_signalForSelector
用户代替代理rac_valuesAndChangesForKeyPath
用于监听某个对象的某个属性的改变rac_signalForControlEvents
用于监听某个事件rac_addObserverForName
用于监听某个通知,且不须要在 - (void)dealloc
中移除监听rac_textSignal
用于监听文本框文字变化rac_gestureSignal
用于监听手势操做rac_liftSelector:withSignalsFromArray:Signals
当传入的 Signals,每个 Signal 都至少 sendNext 过一次,就会去触发第一个 selector 参数的方法。bind
:函数会返回一个新的信号 N。总体思路是对原信号 O 进行订阅,每当信号 O 产生一个值就将其转变成一个中间信号 M ,并立刻订阅 M ,以后将信号M的输出做为新信号 N 的输出。map
\ flattenMap
:用于把源信号内容映射成新的内容(信号)。concat
:组合,按必定顺序拼接信号,当多个信号发出的时候,有顺序的接收信号。then
:用于链接两个信号,当第一个信号完成,才会链接 then
返回的信号。merge
:把多个信号合并为一个信号,任何一个信号有新值的时候就会调用。zipWith
:把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,而且把两个信号的内容合并成一个元组,才会触发压缩流的 next
事件。combineLatest
:将多个信号合并起来,而且拿到各个信号的最新的值,必须每一个合并的 signal
至少都有过一次 sendNext
,才会触发合并的信号。reduce
:聚合,用于信号发出的内容是元组,把信号发出元组的值聚合成一个值。filter
:过滤信号,使用它能够获取知足条件的信号。ignore
:忽略某些值的信号,使用 RACObserve
时可配合使用,其实现由 filter
完成。distinctUntilChanged
:实现是用 bind
来完成的,每次变换中都记录一下原信号上一次发送过来的值,并与这一次进行比较,若是是相同的值,就「吞」掉,返回 empty 信号。只有和原信号上一次发送的值不一样,变换后的新信号才把这个值发送出来。take
:从开始一共取 N 次的信号。takeLast
:取最后 N 次的信号,前提条件:订阅者必须调用完成,由于只有完成,才知道总共有多少信号。takeUntil
:获取信号直到某个信号执行完成。skip
:跳过几个信号,不接受。switchToLatest
:用于 signalOfSignals
(信号的信号),有时候信号也会发出信号,会在 signalOfSignals
中,获取 signalOfSignals
发送的最新信号。doNext
:执行 next
以前,会先执行这个 Block 。doCompleted
:执行 sendCompleted
以前,会先执行这个Block 。timeout
:超时,可让一个信号在必定的时间后,自动报错。interval
:定时:每隔一段时间发出信号。delay
:延迟发送 next
。retry
:重试,只要失败,就会从新执行建立信号中的 block ,直到成功。replay
:重放,当一个信号被屡次订阅,反复播放内容。throttle
:节流,当某个信号发送比较频繁时,可使用节流,在某一段时间不发送信号内容,过了一段时间获取信号的最新内容发出。RAC(TARGET, ...)
用于绑定某个对象的某个属性RACObserve(TARGET, KEYPATH)
用于监听某个对象的某个属性,返回的是信号@weakify(Obj)
& @strongify(Obj)
配套使用Side effects occur for each subscription by default, but there are certain situations where side effects should only occur once – for example, a network request typically should not be repeated when a new subscriber is added.
若是某个信号被多个 subscriber
订阅,那么它的 didSubscribe
会被屡次调用。
若是想要避免这种状况的发生,可使用 reply
/ replayLast
/ replayLazily
方法,它们的做用是保证 signal
只被触发一次,而后把 sendNext:
的 value
给缓存起来,下一次再有新的 subscriber
时,直接发送缓存的 value
。
其内部实现依赖: - (RACMulticastConnection *)multicast:(RACSubject *)subject;
这个方法。
RAC 给 UITableViewCell
提供了一个方法: rac_prepareForReuseSignal
,它的做用是当 Cell 即将要被重用时,告诉 Cell 。想象 Cell 上有多个 Button
,Cell 在初始化时给每一个 Button 都 addTarget:action:forControlEvents
,被重用时须要先移除这些 target ,下面这段代码就能够很方便地解决这个问题:
[[[self.cancelButton
truerac_signalForControlEvents:UIControlEventTouchUpInside]
truetakeUntil:self.rac_prepareForReuseSignal]
truesubscribeNext:^(UIButton *x) {
true// do other things }];
由于 RAC 不少操做都是在 Block
中进行的,因此最多见的问题即是「循环引用」,因此须要经过 @weakify
和 @strongify
来消除循环引用。
注意:事实上 RACObserve(TARGET, KEYPATH)
老是会引用 self
,即便 target 不是 self ,因此只要有 RACObserve 的地方都要使用 @weakify
/ @strongify
。
flattenMap
中的 block 返回信号。map
中的 block 返回对象。map
的实现是用了 flattenMap
函数来实现的。把 map
的入参闭包,放到了 flattenMap
的返回值中。map
。flattenMap
。signalOfsignals
用 flattenMap
。Subject
相似「直播」,错过了就再也不处理。而 Signal
相似「点播」。RACSubject
及其子类是热信号, RACSignal
排除 RACSubject
类之外的是冷信号。RACSubject
会持有订阅者(由于 RACSubject
是热信号,为了保证将来有事件发送的时候,订阅者能够收到信息,因此须要对订阅者保持状态,作法就是持有订阅者),而 RACSignal
不会持有订阅者。当一个 signal
被一个 subscriber
subscribe 后,这个 subscriber
什么时候会被移除?答案是:当 subscriber
被 sendComplete
或 sendError
时,或者手动调用 [disposable dispose]
。
replay
是 multicast
的一个特殊 case 而已。
当 subscriber
被 dispose
后,全部该 subscriber
相关的工做都会被中止或取消,如 http 请求,资源也会被释放。
Errors
有优先权,若是有多个 signals
被同时监听,只要其中一个 signal sendError
,那么 error 就会马上被传送给 subscriber ,并致使 signals 终止执行。至关于 Exception
。
使用 RACSubject
,若是进行了 map
操做,那么必定要发送完成信号,否则会内存泄漏。
任何的信号转换便是对原有的信号进行订阅从而产生新的信号。