RAC类关系图:


RAC 信号源:


需要导入的头文件:

 import ReactiveCocoa
import Result
import ReactiveSwift

冷信号

  //1.冷信号
let producer = SignalProducer<String, NoError>.init { (observer, _) in
print("新的订阅,启动操作")
observer.send(value: "Hello")
observer.send(value: "World")
observer.sendCompleted()
} //创建观察者 (多个观察者观察会有副作用)
let sub1 = Signal<String, NoError>.Observer(value: { (value) in
print("观察者1接受信号\(value)")
}) let sub2 = Signal<String, NoError>.Observer(value: { (value) in
print("观察者2接受信号\(value)")
})
//观察者订阅信号
print("观察者1订阅信号")
producer.start(sub1)
print("观察者2订阅信号")
producer.start(sub2)

结果:


热信号

 //        热信号 (通过管道创建)
let (signalA, observerA) = Signal<String, NoError>.pipe()
let (signalB, observerB) = Signal<Int, NoError>.pipe() Signal.combineLatest(signalA,signalB).observeValues { (value) in
print("两个热信号收到的值\(value.0) + \(value.1)")
}
//订阅信号要在send之前
signalA.observeValues { (value) in
print("signalA : \(value)")
} observerA.send(value: "sssss")
// observerA.sendCompleted()
observerB.send(value: )
// observerB.sendCompleted() observerB.send(value: )
//不sendCompleted和sendError 热信号一直激活
// observerB.sendCompleted()

结果: 


文本框监听

 func racsTest() {
textField.reactive.continuousTextValues.observeValues { (text) in print("值为:\(text ?? "")") }
}

结果:


Map映射 用于将一个事件流的值操作后的结果产生一个新的事件流。

方法一:

textField.reactive.continuousTextValues.map { (text) -> Int in

            return (text?.count)!//!.characters.count

            }.observeValues { (count) in

                print("数值为:\(count)")

        }

输入: Hello123

结果为:

方法二:

 let (signal, observer) = Signal<String, NoError>.pipe()
signal.map { (string) -> Int in
return string.lengthOfBytes(using: .utf8)
}.observeValues { (length) in
print("长度length: \(length)")
} observer.send(value: "") observer.send(value: "some")

结果为:


Filter函数可以按照之前预设的条件过滤掉不满足的值

方法一:

 textField.reactive.continuousTextValues.filter { (text) -> Bool in

             return text!.characters.count > 

             }.observeValues { (text) in

                 print(text ?? "")

         }

输入: 1234

结果:

1234

方法二:

 let (signal, observer) = Signal<Int, NoError>.pipe()
signal.filter { (value) -> Bool in
return value % ==
}.observeValues { (value) in
print("\(value)能被2整除")
}
observer.send(value: )
observer.send(value: )
observer.send(value: )
observer.send(value: )

结果:

4能被2整除

6能被2整除


信号合并

合成后的新事件流只有在收到每个合成流的至少一个值后才会发送出去。接着就会把每个流的最新的值一起输出。

 //        信号合并 两个要被订阅combineLatest 才能被订阅,被订阅后,合并中其中一个sendNext都会激活订阅
let (signalA, observerA) = Signal<String, NoError>.pipe()
let (signalB, observerB) = Signal<Array<Any> , NoError>.pipe()
Signal.combineLatest(signalA, signalB).observeValues { (value) in
print("合并的信号:\(value)")
} observerA.send(value: "xxx")
observerA.sendCompleted()
observerB.send(value: ["sdsd","ddddd"])
observerB.sendCompleted()

结果:


信号联合

zip中的信号都要被订阅才能激活,意味着如果是一个流的第N个元素,一定要等到另外一个流第N值也收到才会一起组合发出。

 //        信号联合
let (signalA, observerA) = Signal<String, NoError>.pipe()
let (signalB, observerB) = Signal<String, NoError>.pipe() //两个到需要订阅 才激活zip
Signal.zip(signalA, signalB).observeValues { (value) in
print("zip: \(value)")
} observerA.send(value: "")
// observerA.sendCompleted()
observerB.send(value: "")
// observerB.sendCompleted()
observerB.send(value: "cc")
observerA.send(value: "dd")

结果:


调度器

    QueueScheduler.main.schedule(after: Date.init(timeIntervalSinceNow: )) {
print("主线程3秒过去了")
}
QueueScheduler.init().schedule(after: Date.init(timeIntervalSinceNow: )) {
print("子线程2秒过去了")
}

结果:


通知

 //        通知
NotificationCenter.default.reactive.notifications(forName: Notification.Name(rawValue: "UIKeyboardWillShowNotification"), object: nil).observeValues { (notification) in
print("键盘弹起")
} NotificationCenter.default.reactive.notifications(forName: Notification.Name(rawValue:"UIKeyboardWillHideNotification"), object: nil).observeValues { (notification) in
print("键盘收起")
}

结果:


KVO

 let result = self.textField.reactive.producer(forKeyPath: "text")
result.start { (text) in
print("----------->\(text)");
}

输入:Hello

注意:输一个字符,Return 一下,否则监听不到

结果:


迭代器

 //        迭代器
let array:[String] = ["name1", "name2"]
var arrayIterator = array.makeIterator()
while let temp = arrayIterator.next() {
print(temp)
} //swift系统自带
array.forEach { (value) in
print("系统自带:\(value)")
}

结果:


on

可以通过 on来观察signal,生成一个新的信号,即使没有订阅者也会被触发。
和 observe相似,也可以只观察你关注的某个事件。
需要提到的是 producer要started后才会触发。

 let signal = SignalProducer<String , NoError>.init { (obsever, _) in
obsever.send(value: "SignalProducer")
obsever.sendCompleted()
} //可以通过 on来观察signal,生成一个新的信号,即使没有订阅者(sp.start())也会被触发。
let sp = signal.on(starting: {
print("开始")
}, started: {
print("结束")
}, event: { (event) in
print("Event: \(event)")
}, failed: { (error) in
print("error: \(error)")
}, completed: {
print("信号完成")
}, interrupted: {
print("信号被中断")
}, terminated: {
print("信号结束")
}, disposed: {
print("信号清理")
}) { (value) in
print("value: \(value)")
} sp.start()

结果:


reduce

reduce将事件里的值聚集后组合成一个值

 let (signal, observer) = Signal<Int, NoError>.pipe()
//reduce后的是聚合的次数
signal.reduce() { (a, b) -> Int in
//a是相乘后的值 b是传入值
print("a:\(a) b:\(b)")
return a * b
}.observeValues { (value) in
print("输出的值是:\(value)")
} observer.send(value: )
observer.send(value: )
observer.send(value: )
//要注意的是最后算出来的值直到输入的流完成后才会被发送出去。
observer.sendCompleted()

结果:


flatten

flatten 将一个事件流里的事件流变成一个单一的事件流。新的事件流的值按照指定的策略(FlattenStrategy)由内部的事件流的值组成。 被压平的值按照会变成外层的流的类型。比如:一个SignalProducers里的Signal,被flatten后的类型是SignalProducers。


合并

简单的说就是merge按照时间顺序组成,concat则是按照里面整个流顺序组合。latest是只记录最近一次过来的值的那个流。

.1 Merge 策略将每个流的值立刻组合输出。无论内部还是外层的流如果收到失败就终止。

 let (producerA, lettersObserver) = Signal<String, NoError>.pipe()
let (producerB, numbersObserver) = Signal<String, NoError>.pipe()
let (signal, observer) = Signal<Signal<String, NoError>, NoError>.pipe()
signal.flatten(.merge).observeValues { (value) in
print("value: \(value)")
}
observer.send(value: producerA)
observer.send(value:producerB)
observer.sendCompleted()
lettersObserver.send(value:"埃及") // prints "a"
numbersObserver.send(value:"") // prints "1"
lettersObserver.send(value:"罗马") // prints "b"
numbersObserver.send(value:"") // prints "2"
lettersObserver.send(value:"瑞典") // prints "c"
numbersObserver.send(value:"") // prints "3"

结果:


.2 Concat 策略是将内部的SignalProducer排序。外层的producer是马上被started。随后的producer直到前一个发送完成后才会start。一有失败立即传到外层。 

 let (signalA, lettersObserver) = Signal<Any, NoError>.pipe()
let (signalB, numberObserver) = Signal<Any, NoError>.pipe() let (siganl, observer) = Signal<Signal<Any, NoError>, NoError>.pipe() siganl.flatten(.concat).observeValues { (value) in
print("value: \(value)")
}
observer.send(value: signalA)
observer.send(value: signalB)
observer.sendCompleted() lettersObserver.send(value: "dddd")//dddd
numberObserver.send(value: ) //不打印是因为lettersObserver的发送值没有结束,所以 44 能打印出来 lettersObserver.send(value: "sss")//sss
lettersObserver.send(value: "ffff")//ffff
lettersObserver.sendCompleted()
//要前一个信号执行完毕后,下一个信号才能被订阅
numberObserver.send(value: )//

结果:

.3 latest只接收最新进来的那个流的值

         let (signalA, lettersObserver) = Signal<Any, NoError>.pipe()
let (signalB, numberObserver) = Signal<Any, NoError>.pipe() let (siganl, observer) = Signal<Signal<Any, NoError>, NoError>.pipe() siganl.flatten(.latest).observeValues { (value) in
print("value: \(value)")
}
observer.send(value: signalA)
// observer.send(value: signalB) lettersObserver.send(value: "dddd") //dddd
numberObserver.send(value: ) //不打印
lettersObserver.send(value: "sss") //sss
observer.send(value: signalB)
//只接受最近进来的信号
numberObserver.send(value: ) //
lettersObserver.send(value: "ffff") // 不打印

结果:


flatMapError

捕捉一个由SignalProducer产生的失败,然后产生一个新的SignalProducer代替。

 let (signal, observer) = Signal<Any, NSError>.pipe()
let error = NSError.init(domain: "domian", code: , userInfo: nil)
signal.flatMapError { (value) -> SignalProducer<Any, NoError> in
return SignalProducer<Any, NoError>.init({ () -> String in
return "sssss"
})
}.observeValues { (value) in
print(value)
} observer.send(value: "无双")
observer.send(value: "鹰眼")
observer.send(error: error)

结果:


retry

retry用于按照指定次数,在失败时重启SignalProducer

 var tries =
let limit =
let error = NSError.init(domain: "

ReactiveCocoa(II)的更多相关文章

  1. ReactiveCocoa入门教程:第一部分

    http://www.cocoachina.com/ios/20150123/10994.html 本文翻译自RayWenderlich,原文:ReactiveCocoa Tutorial--The ...

  2. 使用ReactiveCocoa实现iOS平台响应式编程

    使用ReactiveCocoa实现iOS平台响应式编程 ReactiveCocoa和响应式编程 在说ReactiveCocoa之前,先要介绍一下FRP(Functional Reactive Prog ...

  3. [转]使用ReactiveCocoa实现iOS平台响应式编程

    原文:http://www.itiger.me/?p=38 使用ReactiveCocoa实现iOS平台响应式编程 ReactiveCocoa和响应式编程 在说ReactiveCocoa之前,先要介绍 ...

  4. 走进ReactiveCocoa的世界

    在学习ReactiveCocoa之前,先学习一下概念 ReactiveCocoa 是一套开源的基于Cocoa的FRP框架 .FRP的全称是Functional Reactive Programming ...

  5. iOS开发之ReactiveCocoa下的MVVM(干货分享)

    最近工作比较忙,但还是出来更新博客了,今天给大家分享一些ReactiveCocoa以及MVVM的一些东西,干活还是比较足的.在之前发表过一篇博文,名字叫做<iOS开发之浅谈MVVM的架构设计与团 ...

  6. Leetcode 笔记 113 - Path Sum II

    题目链接:Path Sum II | LeetCode OJ Given a binary tree and a sum, find all root-to-leaf paths where each ...

  7. Leetcode 笔记 117 - Populating Next Right Pointers in Each Node II

    题目链接:Populating Next Right Pointers in Each Node II | LeetCode OJ Follow up for problem "Popula ...

  8. 函数式Android编程(II):Kotlin语言的集合操作

    原文标题:Functional Android (II): Collection operations in Kotlin 原文链接:http://antonioleiva.com/collectio ...

  9. ReactiveCocoa 冷热订阅(cold subscribe, hot subscribe)

    ReactiveCocoa支持两种订阅方式,一种是冷订阅,一种是热订阅. 热订阅的特点: 1.不管有没有消息订阅着,发送者总会把消息发出去. 2.不管订阅者是什么时候订阅的,发送者总是会把相同的消息发 ...

随机推荐

  1. JMeter之http接口测试

    能做哪些类型性能测试 接口 文件传输(ftp) 数据库 支持自定义java组件开发 安装 http://jmeter.apache.org/ 进入上面的链接 选择合适版本下载 启动 使用 Jmeter ...

  2. Python开发【笔记】:从海量文件的目录中获取文件名--方法性能对比

    Python获取文件名的方法性能对比 前言:平常在python中从文件夹中获取文件名的简单方法   os.system('ll /data/')   但是当文件夹中含有巨量文件时,这种方式完全是行不通 ...

  3. linux链接库的理解

    前段时间遇到个奇怪的问题,经调试是由于可执行程序A编译时使用的libssl.so.1.1及对应版本头文件,A链接的库libtest.so编译时使用的libssl.so.1.0及对应版本头文件,执行时l ...

  4. Java+Selenium 如何参数化验证Table表格数据

    场景: 当我们编写脚本时候,需要验证某个表格某一列数据,或者多个列数据. 如果每验证一个就写一个方法,实在是太费事, 因此我们需要有参数化的思想,把某列数据看成固定的元素,然后去验证即可. 1. 示例 ...

  5. expect 自动完成交互式程序神器

    expect 安装 yum -y install expect # Centossudo apt-get install expect # Ubuntu 作用:自动填写交互式程序的值. 原理:通过读取 ...

  6. 帝国cms添加修改会员字段时字段名不能带数字,否则注册页会出现空白

    这几天ytkah在整帝国cms会员模块,根据客户需求添加不同的字段,这个相对不难,可还是遇到了点问题.当时添加会员字段时,在字段名用数字“1”来代表第一次,如下图的字段名“1rwsdy” 但是添加以后 ...

  7. sqlite基本操作

    sqlite准备步骤; .下载:https://www.sqlite.org/download.html: sqlite-dll-win64-3250200.zip 和 sqlite-tools-wi ...

  8. Request实例

    Request常用方法        getRequestURL方法返回客户端发出请求时的完整URL. getRequestURI方法返回请求行中的资源名部分. getQueryString 方法返回 ...

  9. confd动态生成配置文件

    下载安装confd $ mkdir -p $GOPATH/src/github.com/kelseyhightower $ git clone https://github.com/kelseyhig ...

  10. 对接口(interface)的思考

    接口,java中用关键字interface定义.今天学习java基础API时,发现一个特点:每个包中都定义了一堆的接口,感觉有马克思主义中提到的“上层建筑”的味道.接口就是为需要实现的功能定一个基调, ...