函数式响应式编程概述
函数式响应式编程概述
-
满足函数式的一些特性;
如何看待计算,如何避免使用状态量,
-
面向离散事件流
每个对象是个离散事件流。
-
离散事件流操作
什么是ReactiveCocoa?
- Github Mac客户端副产物
- FRP在Cocoa框架下的实现
- 富含了Cocoa框架多种组件
- 提供基于时间变化的数据流的组合和变换
- 简称RAC
如何理解基于时间变化的数据流?
流与数组.png数组:是基于空间变化的数组;
流:是基于时间变化的数据流;
都要考虑:如何创建-如何遍历-如何停止遍历
数组:可以存在一个数组内部封装一个数组,称为多维数组;
流:存在一个流内部封装另一个流,一个流称为一阶,多个嵌套的流称为高阶数据流;
基于时间变化的数据流可操作范围
基于时间的数据流.png流的更多操作
流的更多操作.png函数式编程4特性
- 闭包&高阶函数
- 惰性计算
- 不改变状态
- 递归
高阶函数
入参和返回值都是函数,称这个函数是高阶函数。
闭包
FRP中函数是第一类,和变量等同的概念,int a = 0;
,如果上下文当中有一个a,不管a现在的值是多少,我在函数中会用到a将其捕获进来,让其参与计算,这就意味着每次a不同的时候,就会产生不同的函数,这种情况下就称为闭包
惰性计算
在使用时才会去计算的函数模型。
ReactiveCocoa基础知识
核心框架
-
RACSteam RACSequence RACSignal
-
RACSubscriber
-
RACDisposable
-
RACScheduler
-
Cocoa框架适配工具
Sequence Vs Signal
-
Pull-driver vs Push-driver
Pull-driver 类似于你去看一本书,你想读多少页,书就提供多少页,是你驱动书进行下去的。Push-driver 类似于你看电视,电视不会因为你的任何动作而有所停留,会一直播放节目,相当于一直push。
-
Data vs Event
Sequence是一个id类型只包含数据,Signal是一个id类型,基于信号和事件,信号发出的值不能只是值,还需要有一些状态。signal把数据包含在value里.
-
其他差异
Sequence 和 Signal都是基于惰性计算的,效率各有不同,Sequence在空间中是连续的,进行大量的运算CPU消耗会比较高,Signal是离散的,离散就可以把计算分摊在很多的CPU循环的时间上
RACSequence使用示例
void sequence() {
//创建三种方式
RACSequence *seq1 = [RACSequence return:@1];
RACSequence *seq2 = [RACSequence sequenceWithHeadBlock:^id _Nullable{
return @1;
} tailBlock:^RACSequence * _Nonnull{
return seq1;
}];
RACSequence *seq3 = @[@1,@2,@3].rac_sequence;
//变换
RACSequence *mappedSeq = [seq1 map:^id _Nullable(NSNumber * _Nullable value) {
return @(value.integerValue * 3);
}];
RACSequence *concatedSeq = [seq2 concat:mappedSeq];
RACSequence *mergedSeq = [RACSequence zip:@[concatedSeq, seq3]];
NSLog(@"head is %@",mergedSeq.head);
//遍历
for (id value in mergedSeq) {
NSLog(@"value is %@", value);
}
}
RACSignal
- (void)signalExample
{
//创建
RACSignal *signal1 = [RACSignal return:@"hello"];
RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@1];
[subscriber sendNext:@2];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signal3 = RACObserve(self, value);
//变换
RACSignal *mappedSignal = [signal1 map:^id _Nullable(NSString* _Nullable value) {
return [value stringByAppendingString:@" world"];
}];
RACSignal *concatedSignal = [mappedSignal concat:signal2];
RACSignal *mergeSignal = [RACSignal merge:@[concatedSignal, signal3]];
//遍历
[mergeSignal subscribeNext:^(id _Nullable x) {
NSLog(@"next is %@", x);
} completed:^{
NSLog(@"completed");
}];
}
Signal Subscriber Disposable
signal_subscriber_disposable.pngSubscriber订阅Signal,写的一些值,这些Block块由Subscriber持有,Disposable负责在不持有的时候断开。
Scheduler
-
用来做调度
什么时间在什么线程中执行就称为调度
-
代替GCD
-
异步与并发
总结
怎么理解函数式语言中的引用透明?
数学里的概念向计算机里的投射,引用透明表示一个函数具有数学中的函数意义,也就是说这个函数只根据他的因变量(参数)而产生结果,即这个函数在执行的过程中既不改变这个变量,也不基于这个变量。使用相同的参数对这样的一个函数进行多次调用,会得到相同的结果。
函数式语言主张不变量的原因是什么?
- 为了保证跟数学模型的亲密性。
- 编译器更好的优化