博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ReactiveCocoa Swift部分入门指南 Signal
阅读量:6850 次
发布时间:2019-06-26

本文共 9031 字,大约阅读时间需要 30 分钟。

原文地址: 简书只做同步更新功能


学习过ReactiCocoa(以下简称RAC)的同学一般都会使用Objective-C的部分,不过RAC3之后支持了Swift,目前RAC3.x支持的是Swift1.x系列,RAC4支持的是Swift2.x系列。今天花了一点时间学习了下Swift部分示例代码。这里做些记录。Swift是支持playground,可以使用Markdown编写文档,并且所见即所得的界面方便学习。更可以插入图片。方便阅读。

学习知识必备

默认你已经学过RAC-OC部分, Swift语言,并对Monad,functional Programming有些简单的了解,或者,如果你学习了RXSwift更好。

Start

1.	git clone  git@github.com:ReactiveCocoa/ReactiveCocoa.git	•	执行script/bootstrap 脚本	•	如果你安装了 [Cartheage](https://github.com/Carthage/Carthage) 使用  carthage checkout2.	打开 ReactiveCocoa.xcworkspace3.	编译 Result-Mac scheme4.	编译 ReactiveCocoa-Mac scheme5.	在workSpace目录中打开ReactiveCocoa.playground6.	Choose View > Show Debug Area、复制代码

PlaygroundUtility

先来观察一下这个里面有两个方法

public func scopedExample(exampleDescription: String, _ action: () -> Void) {	print("\n--- \(exampleDescription) ---\n")	action()}public enum Error: ErrorType {	case Example(String)}复制代码

scopedExample 方便测试,并分割日志输出,Error也是为了测试方便。

Signal

一个Signal类型的实例,代表了一个有时序的并且可以被观察 (类似订阅)的事件流

信号通常被用来表示正在进行中的事件流,比如通知用户输入等。用户(或者只要能造成事件的东西)产生的事件发送或者被接受,事件就被传递到信号上,并且被推送(push -Driven)到任何观察者哪里,并且所有观察者都是同时收到这些事件。

如果你想访问一系列的事件,就必须观察一个信号,观察一个信号并不会触发任何附作用,可以这样理解。信号是由生产者生产和推动(push)的,消费者(观察者)是不会对事件的生命周期有任何影响。在观察一个信号时,发送了什么事件,只能对这个事件做操作,因为信号是有时序的,不能随机的访问其他事件。

信号可以通过原函数去操作,比如 filtermapreduce,也可以同时操作多个信号如zip,这些原函数只在 nextEvents生效(也就是对 comlete,failure等不生效)。 在一个信号的生命周期里,可以发送无数次的NextEvents事件,直到他们被终结,类似compleye,Faied,InterRuppet。终止事件没有数据值,所以他们必须被单独处理。

Subscription

一个信号通常被用来表示正在进行中的事件流,有时候他们被叫做热信号,这意味这订阅者可以错过一些在它订阅前发送的事件。订阅一个信号不会触发任何附作用。

scopedExample("Subscription") {            // Signal.pipe is a way to manually control a signal. the returned observer can be used to send values to the signal            let (signal, observer) = Signal
.pipe() let subscriber1 = Observer
(next: { print("Subscriber 1 received \($0)") }) let subscriber2 = Observer
(next: { print("Subscriber 2 received \($0)") }) print("Subscriber 1 subscribes to the signal") print("\(observer)") signal.observe(subscriber1) print("Send value `10` on the signal") // subscriber1 will receive the value observer.sendNext(10) print("Subscriber 2 subscribes to the signal") // Notice how nothing happens at this moment, i.e. subscriber2 does not receive the previously sent value signal.observe(subscriber2) print("Send value `20` on the signal") // Notice that now, subscriber1 and subscriber2 will receive the value observer.sendNext(20) } --- Subscription ---Subscriber 1 subscribes to the signalObserver
(action: (Function))Send value `10` on the signalSubscriber 1 received 10Subscriber 2 subscribes to the signalSend value `20` on the signalSubscriber 1 received 20Subscriber 2 received 20复制代码

因为Swift有泛型的存在,这样的话我们可以把Signal当作任何数据类型的容器,而不是像OC中利用上帝类型(id)。更加方便传递数据。

首先我们通过Siganl.pipe()创建了一个信号和一个观察者。 奇怪的是,在RACOC部分中,我们很少主动创建观察者,我们通常直接订阅信号就可以。 在Siwft中,通过pipe创建的信号是个热信号,类似与OC中的RACSubject系列,在RACSubject继承自RACSiganl又继承自RACStream,RACStream是一个Monad,它可以代表数据和数据的一系列的操作如map,flattenMap,bind RACSubject又遵守了RACSubscriber协议,这个协议定义了可以发送数据的操作。 所以RACSubject即是一个信号,又是一个观察者。

在Swift部分的实现中,Signal并没有实现发送数据的方法。所以它需要一个内部的Observer去发送数据。所以它被pipe直接返回,

在外部我们需要自己实例化一个Observer观察者。去观察(订阅)事件,

可能在你查看pipe的实现的时候并不太好理解。把尾随闭包补全相对好理解点。

做个总结

  1. RACOC中:

RACSubject = RACSignal + RACSubscriper 在订阅的时候,订阅者被放在了RACSubject内部存放,我们只需要去关注订阅的block实现即可。

  1. RACSwift中:

Signal:Just is a Signal 所以需要一个内部观者者去充当发送数据的工具。外部的订阅需要自己手动实例观察者

  1. 热信号:

由于pipe方法返回的是热信号,所以一个订阅者会错过在订阅之前发送的事件。

empty

空信号直接发送一个interrupted事件

scopedExample("`empty`") {            let emptySignal = Signal
.empty let observer = Observer
( failed: { _ in print("error not called") }, completed: { print("completed not called") }, interrupted: { print("interrupted called") }, next: { _ in print("next not called") } ) emptySignal.observe(observer) } --- `empty` ---interrupted called 复制代码

Never

一个never信号不会发送任何事件

scopedExample("`never`") {    let neverSignal = Signal
.never let observer = Observer
( failed: { _ in print("error not called") }, completed: { print("completed not called") }, interrupted: { print("interrupted not called") }, next: { _ in print("next not called") } ) neverSignal.observe(observer)}--- `never` ---复制代码

Operators

uniqueValues 唯一值

仅从集合中发送一次相同事件---类似与arrryQueue变成了SetQueue

注意:这会造成被发送的值被保留下来,用于以后发送的时候来检查是否重复,你可以编写一个函数来过滤重复值,这样可以减少内存消耗。

scopedExample("`uniqueValues`") {    let (signal, observer) = Signal
.pipe() let subscriber = Observer
(next: { print("Subscriber received \($0)") } ) let uniqueSignal = signal.uniqueValues() uniqueSignal.observe(subscriber) observer.sendNext(1) observer.sendNext(2) observer.sendNext(3) observer.sendNext(4) observer.sendNext(3) observer.sendNext(3) observer.sendNext(5)}--- `uniqueValues` ---Subscriber received 1Subscriber received 2Subscriber received 3Subscriber received 4Subscriber received 5复制代码

map

把每一个发送的值转换成新的值

scopedExample("`map`") {    let (signal, observer) = Signal
.pipe() let subscriber = Observer
(next: { print("Subscriber received \($0)") } ) let mappedSignal = signal.map { $0 * 2 } mappedSignal.observe(subscriber) print("Send value `10` on the signal") observer.sendNext(10)}--- `map` ---Send value `10` on the signalSubscriber received 20复制代码

mapError

把收到的error值变成新的error值

scopedExample("`mapError`") {            let userInfo = [NSLocalizedDescriptionKey: "?"]        let code = error.code + 10000        let mappedError = NSError(domain: "com.reactivecocoa.errordomain", code: code, userInfo: userInfo)    let (signal, observer) = Signal
.pipe() let subscriber = Observer
(failed: { print("Subscriber received error: \($0)") } ) let mappedErrorSignal = signal.mapError { (error:NSError) -> NSError in return mappedError } mappedErrorSignal.observe(subscriber) print("Send error `NSError(domain: \"com.reactivecocoa.errordomain\", code: 4815, userInfo: nil)` on the signal") observer.sendFailed(NSError(domain: "com.reactivecocoa.errordomain", code: 4815, userInfo: nil))}--- `mapError` ---Send error `NSError(domain: "com.reactivecocoa.errordomain", code: 4815, userInfo: nil)` on the signalSubscriber received error: Error Domain=com.reactivecocoa.errordomain Code=14815 "?" UserInfo={
NSLocalizedDescription=?}复制代码

filter

用于过滤一些值

scopedExample("`filter`") {    let (signal, observer) = Signal
.pipe() let subscriber = Observer
(next: { print("Subscriber received \($0)") } ) // subscriber will only receive events with values greater than 12 let filteredSignal = signal.filter { $0 > 12 ? true : false } filteredSignal.observe(subscriber) observer.sendNext(10) observer.sendNext(11) observer.sendNext(12) observer.sendNext(13) observer.sendNext(14)}--- `filter` ---Subscriber received 13Subscriber received 14复制代码

ignoreNil

在发送的值为可选类型中:如果有值,把值解包,如果是nil 丢弃掉。

scopedExample("`ignoreNil`") {    let (signal, observer) = Signal
.pipe() // note that the signal is of type `Int?` and observer is of type `Int`, given we're unwrapping // non-`nil` values let subscriber = Observer
(next: { print("Subscriber received \($0)") } ) let ignoreNilSignal = signal.ignoreNil() ignoreNilSignal.observe(subscriber) observer.sendNext(1) observer.sendNext(nil) observer.sendNext(3)}--- `ignoreNil` ---Subscriber received 1Subscriber received 3复制代码

take

take(num)只取前num此值的信号

scopedExample("`take`") {    let (signal, observer) = Signal
.pipe() let subscriber = Observer
(next: { print("Subscriber received \($0)") } ) let takeSignal = signal.take(2) takeSignal.observe(subscriber) observer.sendNext(1) observer.sendNext(2) observer.sendNext(3) observer.sendNext(4)}--- `take` ---Subscriber received 1Subscriber received 2复制代码

collect

在发送complete事件之后,观察者会收到一个由之前事件组成的数组,

注意: 如果在发送cimplete事件的时候,没有任何事件发送,观察者会收到一个空的数组

scopedExample("`collect`") {    let (signal, observer) = Signal
.pipe() // note that the signal is of type `Int` and observer is of type `[Int]` given we're "collecting" // `Int` values for the lifetime of the signal let subscriber = Observer<[Int], NoError>(next: { print("Subscriber received \($0)") } ) let collectSignal = signal.collect() collectSignal.observe(subscriber) observer.sendNext(1) observer.sendNext(2) observer.sendNext(3) observer.sendNext(4) observer.sendCompleted()}--- `collect` ---Subscriber received [1, 2, 3, 4]复制代码

Signal大致讲解到这里结束了。给自己挖个坑,下一篇整理下


最后再来个广告 受到 公众号主人邀请 我的文章也会被发布到这个公众号

** 加个欢迎微信扫码关注吧**复制代码

转载地址:http://wulul.baihongyu.com/

你可能感兴趣的文章
锚点定位偏移问题
查看>>
QTP的那些事—WMI+SQL分析查询工具
查看>>
柯里化
查看>>
LeetCode - Nth Highest Salary
查看>>
海量数据面试题整理
查看>>
9.ORM数据访问
查看>>
第三次作业结对编程
查看>>
sublime使用
查看>>
一言不合就动手系列篇一-仿电商平台前端搜索插件(filterMore)
查看>>
Oracle Split 函数
查看>>
目标跟踪之卡尔曼滤波---理解Kalman滤波的使用预测
查看>>
Git安装和基本使用(1)
查看>>
Swoft 图片上传与处理
查看>>
BluetoothClass详解
查看>>
Centos 7安装Python3.6
查看>>
Django 学习笔记
查看>>
20172303 2017-2018-2 《程序设计与数据结构》实验三报告
查看>>
CSS自定义文件上传按钮
查看>>
排序算法概览(二)
查看>>
document对象获取例子
查看>>