加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

函数响应式编程(FRP)与 ReactiveCocoa

发布时间:2020-12-15 06:46:06 所属栏目:百科 来源:网络整理
导读:前言 应用通常会消费、制造和更新数据。响应式编程是一种编程范式,能够表示数据流,而无需担心副作用或对其他并发执行的任务造成影响。 响应式编程背后的核心思想是随时间流逝体现数据的值。使用动态值的数据流会导致这些值随着时间而变化。 函数响应式编程

前言

应用通常会消费、制造和更新数据。响应式编程是一种编程范式,能够表示数据流,而无需担心副作用或对其他并发执行的任务造成影响。

响应式编程背后的核心思想是随时间流逝体现数据的值。使用动态值的数据流会导致这些值随着时间而变化。

函数响应式编程(functional reactive programmingFRP)允许响应式编程使用内建的块方法进行函数式编程,如mapreducefiltermerge,等等。

ReactiveCocoa 的灵感来自 FRP。因为多组件的应用以高内聚的方式工作,所以组件状态的使用和更新就有了很强的关联。正因为这一点,创建一个低耦合、高内 聚的响应式系统才显得尤为重要。

现在有下面4个概念:

面向对象编程 Object Oriented Programming
响应式编程 Reactive Programming
函数式编程 Functional Programming
函数响应式编程 Functional Reactive Programming


Reactive Cocoa 是一个重量级框架,非常的牛,为什么说Reactive Cocoa非常的牛?
我们所熟知的iOS 开发中的事件包括:

  • Target
  • Delegate
  • KVO
  • 通知
  • 时钟
  • 网络异步回调

ReactiveCocoa ,就是用信号接管了iOS 中的所有事件;也就意味着,用一种统一的方式来处理iOS中的所有事件,解决了各种分散的事件处理方式,显然这么一个庞大的框架学习起来也会比较难!

先看一个图:


从这张图中,可以看出利用信号,ReactiveCocoa接管iOS 的所有事件,抛给开发者对事件作出三个相应反应;

可以用一张图来简要说明


RAC 的特点

  • 通过 block 函数式 + 链式 的编程,可以让所有相关的代码继承在一起!

  • 使用时需要注意循环引用,@weakify(self) / @strongify(self) 组合解除循环引用;
下面用iOS开发中常见的五种事件来说明ReactiveCocoa的常见用法!

下载框架:

  • 新建iOS工程
  • 进入终端,建立 Podfile,并且输入以下内容


在终端输入以下命令安装框架

$ pod install


常见用法

KVO 监听

程序实现: 监控Person name的属性变化;在touchesBegan中改变name的值,并将变化体现在UILabel上,实现KVO的监控功能;

  • 注意,RAC 的信号一旦注册不会主动释放
  • 只要在 block 中包含有 self. 一定会出现强引用* 需要使用 @weakify(self) / @strongify(self) 组合使用解除强引用




文本框输入事件监听






文本框组合信号



按钮监听

按钮点击后看日志输出



代理方法




通知

viewDidLoad 中添加


高级用法

1. flattenMapmap



merge:把多个信号合并成一个信号,只需订阅这一个信号就相当于订阅了多个信号,任何一个信号有新值的时候都会触发调用。


concat:将多个信号有顺序的连接起来,按照顺序接收信号,但是一定要之前的信号完成了才能发送下一个信号。


then:用于连接两个信号,内部也是使用concat,当前一个信号完成之后才会连接then返回的信号,但是会忽略前一个信号,只会触发下个信号。


zip:将对各信号压缩成一个信号,只有当几个信号同时sendNext的时候才会触发压缩流的next事件,其中每一个信号send的内容都是一一对应的。


combineLatest:将多个信号组合起来,当其中每一个信号都sendNext之后,才会触发组合的信号,其中每一个信号再次sendNext都会覆盖之前的信号内容,返回的是一个RACTuple(元组,类似于NSArray)。


rac_liftSelector: withSignalsFromArray::当信号组中每一个信号都至少一次sendNext之后,将触发Selector方法,类似于combineLatest



reduceEach:一般用于元组,把元组的值聚合成一个值。


filter:过滤信号,添加筛选条件,只有符合的才会触发调用。


distinctUntilChanged:当前值跟上一次的值不同的时候,就会触发调用,否则被忽略。


take:从第一个信号开始设置信号发送的有效的个数。


takeLast:从最后一个开始设置信号发送的有效个数,必须sendCompleted,不然不知道总共多少个信号。


takeUntil[signal1 takeUntil:signal2],当signal2已经sendNext或者sendCompleted,signal1就会失效。


skip:跳跃,从第一个发出的信号开始跳。

doNext:在执行sendNext之前会执行这个。

timeout:在超过设定时间范围之后让信号报错,且不能发送内容。

interval:定时,每隔一定时间发出时间信号。


delay:延时发送信号

retry:重试,只要失败,就会重新执行创建信号中的block,直到成功。


throttle:节流,当某个信号发送比较频繁的时候,可以限制在一定之间内不接受信号,等过了这个时间再取最后发送的信号内容发出,类似于bufferWithTime:onScheduler:

deliverOn:内容传递切换到指定线程中,副作用在原来线程中,把在创建信号时block中的代码称之为副作用。

subscribeOn:内容传递和副作用都会切换到指定线程中。


RACSubject

信号提供者,本身可以充当信号,又能发送信号,继承自RACSignal,但是底层实现跟RACSignal有些不一样,当订阅信号的时候会创建订阅者并保存订阅响应Block,而发送信号的时候会遍历订阅者,然后分别调用nextBlock。它提供的API很少,但是经常使用,因为它继承自RACSignal。这里顺便来看一下方法flattenswitchToLatest,这两个都只能用来处理信号中的信号。

flatten:压平信号中的信号,信号中的信号我们称之为子信号,flatten可以拿到所有子信号发送的值。

switchToLatest:与flatten相同,压平信号中的信号,不同的是,在存在多个子信号时候只会拿到最新的子信号,然后输出最新的子信号的




RACReplaySubject

重复提供信号类,继承自RACSubject,它可以先发送信号,再订阅信号,原理就是 将发送的信号内容保存了起来,当订阅信号的时候再将之前保存的信号,由订阅者一个一个的发送出来,而保存信号的容量由capacity来控制。


RACMulticastConnection

这是一个组播连接类,是对信号的一个封装处理,当一个信号被多次订阅时,则会多次执行didSubscribe这个Block,造成副作用,而这个类就能避免多次执行didSubscribe,是一对多的单向数据流,一般用来处理信号被多次订阅的情况。



方法解析及实现原理
  • publishmulticast:这是对RACMulticastConnection初始化方法的一个封装,publish其实就是调用了multicast,并把创建好的RACSubject对象传给它,而multicast也就是调用了RACMulticastConnection的初始化方法,将原始信号传给source,把RACSubject对象传给subject
  • 当我们订阅connect.signal,其实就是订阅subject,然后将subject的订阅者保存起来,而调用[connect connect]的时候,会订阅原始信号(source),而source的订阅者就是subject,这时候subject就会执行[subject sendNext],之后就会遍历subject所有的订阅者,逐一发送信号,触发外部subscribeNext回调。

RACCommand

这是一个命令类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程,一般来说是在UI上的某些动作来触发这些事件,比如点击一个按钮,RACCommand的实例能够决定是否可以被执行,一般用于网络请求,监控请求过程。


RACChannel

这是一个通道类,可以理解为一个双向的连接,连接的两端都配有RACChannelTerminal(通道终端,继承自RACSignal,且又实现了RACSubscriber协议,所以它可以充当信号,又能发送信号),分别是leadingTerminalfollowingTerminal,只要其中任何一端输出信号,另一端都会有相同的信号输出。我们平时很少直接使用RACChannel,而是使用RACChannelTo

RACChannelTo:使用这个宏要传入相关对象以及它的属性,比如RACChannelTo(view,backgroundColor),实际上创建了一个RACKVOChannel对象,在内部将其一端的leadingTerminalviewbackgroundColor属性进行绑定,并将其另一端followingTerminal暴露出来,也就是RACChannelTo的返回值,我们可以对followingTerminal进行订阅,拿到view. backgroundColor,同样followingTerminal发送信号也会同步到view.backgroundColor

用它来实现双向绑定,RACChannelTo(button,backgroundColor) =RACChannelTo(view,backgroundColor);buttonview的背景颜色进行绑定,两边相互影响,进行同步。


代码如下:


运行效果:

没有绑定前

绑定后:点击事件未触发

触发点击事件



常用宏

RAC(TARGET,...):给某个对象的某个属性进行绑定。

//当textfield开始编辑时,关闭button响应

RAC(_button,enabled) = [[self rac_signalForSelector:@selector(textFieldDidBeginEditing:) fromProtocol:@protocol(UITextFieldDelegate)] mapReplace:@NO];


RACObserve(TARGET,KEYPATH):KVO,监听某个对象的属性,返回的是信号。

RACChannelTo:用于双向绑定的一个通道终端。



RACTuplePack:将数据包装成RACTuple(元组)。



RACTupleUnpack(...):把元组解包成对应的数据




demo

https://github.com/kangxg/ThreadLock.git

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读