ReactiveCocoa(简称为RAC),是由Github
开源的一个应用于iOS和OS开发的函数式响应式编程框架,它提供了一系列用来组合和转换值流的 APIhtml
学习一个框架以前, 首先要了解这个框架的编程思想, 这里在介绍响应式编程思想以前, 先介绍一下以前接触过的编程思想ios
C++
, C#
, Java
等ReactiveCocoa
编程思想Functional Programming
Reactive Programming
因此, ReactiveCocoa
被描述为函数响应式编程(FRP)框架, 下面具体介绍一下RAC
的一些常见类git
ReactiveCocoa
中最核心的概念之一就是信号RACStream
。RACStream
中有两个子类——RACSignal
和 RACSequence
; 这里咱们就主要说一下RACSignal
;ReactiveCocoa
整个库中,RACSignal
占据着比较重要的位置,而RACSignal
的变换操做更是整个RACStream
流操做核心之一RACSignal
被订阅的完整过程- (void)test2 {
//建立信号
RACSignal *single = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//发送消息
[subscriber sendNext:@"a"];
[subscriber sendNext:@"b"];
//发送完成
[subscriber sendCompleted];
//清空数据
return [RACDisposable disposableWithBlock:^{
//当订阅者被消耗的时候就会执行
//当订阅者发送完成,或者error的时候也会执行
NSLog(@"RACDisposable的block");
}];
}];
//订阅信号
RACDisposable *disposable = [single subscribeNext:^(id _Nullable x) {
NSLog(@"value = %@", x);
} error:^(NSError * _Nullable error) {
NSLog(@"error: %@", error);
} completed:^{
NSLog(@"completed");
}];
//释放
[disposable dispose];
}
复制代码
RACSignal
的一些子类
RACDynamicSignal
: 动态信号,使用一个 block
来实现订阅行为,咱们在使用 RACSignal
的 +createSignal:
方法时建立的就是该类的实例RACEmptySignal
:空信号,用来实现 RACSignal
的 +empty
方法;RACReturnSignal
:一元信号,用来实现 RACSignal
的 +return:
方法;RACErrorSignal
:错误信号,用来实现 RACSignal
的 +error:
方法;RACChannelTerminal
:通道终端,表明 RACChannel
的一个终端,用来实现双向绑定
RACSignal
在建立信号的时候,底层会调用RACDynamicSignal
的createSignal
的方法, 以下:github
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
return [RACDynamicSignal createSignal:didSubscribe];
}
复制代码
这里的block是一个 id<RACSubscriber>
类型的subscriber
, 而这个RACSubscriber
, 咱们能够点进去看一些底层实现, 协议方法以下:编程
@protocol RACSubscriber <NSObject>
@required
/// Sends the next value to subscribers.
- (void)sendNext:(nullable id)value;
/// Sends the error to subscribers.
- (void)sendError:(nullable NSError *)error;
/// Sends completed to subscribers.
- (void)sendCompleted;
/// Sends the subscriber a disposable that represents one of its subscriptions.
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable;
复制代码
didSubscribe
保存到信号中,还不会触发。signal
的subscribeNext:nextBlock
subscribeNext
内部会建立订阅者subscriber
,而且把nextBlock
保存到subscriber
中。subscribeNext
内部会调用siganl的didSubscribe
[subscriber sendCompleted];
[RACDisposable disposable]
取消订阅信号siganl
的didSubscribe
中调用[subscriber sendNext:@1];
sendNext
底层其实就是执行subscriber
的nextBlock
RACSubject
RACSubject
简单使用- (void)setRacSubject1 {
//先订阅, 在发送信号
//1. 建立信号
RACSubject *subject = [RACSubject subject];
//2. 订阅
//内部建立RACSubscriber
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"第一个订阅者--%@", x);
}];
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"第二个订阅者---%@", x);
}];
//3. 发送信号
//遍历全部的订阅者, 执行nextBlock
[subject sendNext:@2];
/** 打印结果 2018-03-17 20:18:19.782119+0800 ReactiveObjc[23883:1420936] 第一个订阅者--2 2018-03-17 20:18:19.784715+0800 ReactiveObjc[23883:1420936] 第二个订阅者---2 */
}
复制代码
subscribeNext
订阅信号,只是把订阅者保存起来,而且订阅者的nextBlock
已经赋值了。sendNext
发送信号,遍历刚刚保存的全部订阅者,一个一个调用订阅者的nextBlock
RACReplaySubject
简单使用capacity
数量来限制缓存的value
的数量,即只缓充最新的几个值- (void)setReplaySubject {
//建立信号
RACReplaySubject *replySub = [RACReplaySubject subject];
//发送信号
[replySub sendNext:@23];
[replySub sendNext:@34];
//订阅信号
// 遍历值,让一个订阅者去发送多个值
// 只要订阅一次,以前全部发送的值都能获取到.
[replySub subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
/** 2018-03-19 12:01:14.112253+0800 ReactiveObjc[5130:446958] 23 2018-03-19 12:01:14.112511+0800 ReactiveObjc[5130:446958] 34 */
}
复制代码
RACReplaySubject
的底层实现
capacity
决定,这也是有别于RACSubject的View
的时候, 更换vc的背景颜色在自定义View中设置协议缓存
#import <UIKit/UIKit.h>
@class SubjectView;
@protocol SubjectDelegate <NSObject>
@optional
- (void)viewWithTap:(SubjectView *)subView;
@end
@interface SubjectView : UIView
@property (nonatomic, weak) id<SubjectDelegate> delegate;
@end
复制代码
在vc中, 遵循代理, 并实现代理方法框架
/// 代理方法
-(void)viewWithTap:(SubjectView *)subView{
NSLog(@"完成代理, 点击了view");
UIColor *color = [UIColor colorWithRed:(arc4random() % 255) / 255.0 green:(arc4random() % 255) / 255.0 blue:(arc4random() % 255) / 255.0 alpha:1.0];
self.view.backgroundColor = color;
}
复制代码
RACSubject
代替代理在自定义SubjectView.h
文件中dom
#import <UIKit/UIKit.h>
#import <ReactiveObjC.h>
@interface SubjectView : UIView
@property (nonatomic, strong) RACSubject *subject;
@end
复制代码
在自定义SubjectView.m
文件中编程语言
#import "SubjectView.h"
@implementation SubjectView
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//发送信号
[_subject sendNext:self];
}
@end
复制代码
下面看一下在vc中的操做函数式编程
- (void)setupSubjectView {
SubjectView *subV = [[SubjectView alloc]init];
subV.backgroundColor = [UIColor redColor];
subV.frame = CGRectMake(100, 100, 100, 100);
RACSubject *subject = [RACSubject subject];
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"完成代理, 点击了view");
UIColor *color = [UIColor colorWithRed:(arc4random() % 255) / 255.0 green:(arc4random() % 255) / 255.0 blue:(arc4random() % 255) / 255.0 alpha:1.0];
self.view.backgroundColor = color;
}];
subV.subject = subject;
[self.view addSubview:subV];
}
复制代码