文章出自此链接
最近再重新学习swift,从OC的RAC转到Swift的RAC方法调用大变样,各种的不适应。
简单了解
转换的类型有:
RACSignal 和 SignalProducer、 Signal
RACCommand 和 Action
RACScheduler 和 SchedulerType
RACDisposable 和 Disposable
需使用的头文件
import ReactiveCocoa
import Result
import ReactiveSwift
框架组成:
1.事件(Event)
2.监听器(Observer)
3.清洁者(Disposable)
4.信号(Signal)
5.管道:(Pipes)
6.信号生产者:(Signal Producers)
7.缓冲:(Buffers)
8.动作:(Actions)
9.属性:(Properties)
10.调度器:(Schedulers)
从OC的RAC转到Swift的RAC方法调用大变样.
1.冷信号
func bindSignal1(){
//1.冷信号
let producer = SignalProducer.init { (observer, _) in
print("新的订阅,启动操作")
observer.send(value: "Hello")
observer.send(value: "World")
observer.sendCompleted()
}
//创建观察者 (多个观察者观察会有副作用)
let sub1 = Observer(value: {
print("观察者1接受信号\($0)")
})
let sub2 = Observer(value: {
print("观察者2接受信号\($0)")
})
//观察者订阅信号
print("观察者1订阅信号")
producer.start(sub1)
print("观察者2订阅信号")
producer.start(sub2)
}
2.热信号
func bindSignal2(){
//2.热信号 (通过管道创建)
let (signalA, observerA) = Signal.pipe()
let (signalB, observerB) = Signal.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: 2)
// observerB.sendCompleted()
observerB.send(value: 100)
//不sendCompleted和sendError 热信号一直激活
// observerB.sendCompleted()
}
3.监听文本框
func bindSignal3(){
//2文本输入框的监听
nameTF.reactive.continuousTextValues.observeValues { (text) in
print(text ?? "")
}
//监听黏贴进来的文本
let result = nameTF.reactive.values(forKeyPath: "text")
result.start { (text) in
print(text)
}
//按钮监听
loginBtn.reactive.controlEvents(.touchUpInside).observeValues { (button) in
print("点击ann")
}
}
4.信号合并
合成后的新事件流只有在收到每个合成流的至少一个值后才会发送出去。接着就会把每个流的最新的值一起输出。
func bindSignal4(){
//4.信号合并 两个要被订阅combineLatest 才能被订阅,被订阅后,合并中其中一个sendNext都会激活订阅
let (signalA, observerA) = Signal.pipe()
let (signalB, observerB) = Signal , NoError>.pipe()
Signal.combineLatest(signalA, signalB).observeValues { (value) in
print("合并的信号:\(value)")
}
observerA.send(value: "xxx")
observerA.sendCompleted()
observerB.send(value: ["sdsd","ddddd"])
observerB.sendCompleted()
}
5.信号联合
zip中的信号都要被订阅才能激活,意味着如果是一个流的第N个元素,一定要等到另外一个流第N值也收到才会一起组合发出。
func bindSignal5(){
//5.信号联合
let (signalA, observerA) = Signal.pipe()
let (signalB, observerB) = Signal.pipe()
//两个到需要订阅 才激活zip
Signal.zip(signalA, signalB).observeValues { (value) in
print("zip: \(value)")
}
observerA.send(value: "1")
// observerA.sendCompleted()
observerB.send(value: "2")
// observerB.sendCompleted()
observerB.send(value: "cc")
observerA.send(value: "dd")
}
6.调度器
func bindSiganl6() {
//6.调度器
QueueScheduler.main.schedule(after: Date.init(timeIntervalSinceNow: 3)) {
print("主线程3秒过去了")
}
QueueScheduler.init().schedule(after: Date.init(timeIntervalSinceNow: 2)) {
print("子线程2秒过去了")
}
}
7.通知
func bindSignal7(){
//7.通知
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("键盘收起")
}
}
8.KVO
func bindSignal8(){
//8KVO
let result = self.nameTF.reactive.values(forKeyPath: "text")
result.start { (text) in
print(text);
}
}
9.迭代器
func bindSignal9() {
//9.迭代器
let array:[String] = ["name1", "name2"]
var arrayIterator = array.makeIterator()
while let temp = arrayIterator.next() {
print(temp)
}
//swift系统自带
array.forEach { (value) in
print(value)
}
}
10.on
可以通过 on来观察signal,生成一个新的信号,即使没有订阅者也会被触发。
和 observe相似,也可以只观察你关注的某个事件。
需要提到的是 producer要started后才会触发。
let signal = SignalProducer.init { (obsever, _) in
obsever.send(value: "ddd")
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()
打印结果:
开始
Event: VALUE ddd
value: ddd
Event: COMPLETED
信号完成
信号结束
信号清理
结束
11.Map
Map映射 用于将一个事件流的值操作后的结果产生一个新的事件流。
let (signal, observer) = Signal.pipe()
signal.map { (string) -> Int in
return string.lengthOfBytes(using: .utf8)
}.observeValues { (length) in
print("length: \(length)")
}
observer.send(value: "lemon")
observer.send(value: "something")
12.filter
//filter函数可以按照之前预设的条件过滤掉不满足的值
let (signal, observer) = Signal.pipe()
signal.filter { (value) -> Bool in
return value % 2 == 0
}.observeValues { (value) in
print("\(value)能被2整除")
}
observer.send(value: 3)
observer.send(value: 4)
observer.send(value: 6)
observer.send(value: 7)
13.reduce
reduce将事件里的值聚集后组合成一个值
let (signal, observer) = Signal.pipe()
//reduce后的是聚合的次数
signal.reduce(3) { (a, b) -> Int in
//a是相乘后的值 b是传入值
print("a:\(a) b:\(b)")
return a * b
}.observeValues { (value) in
print(value)
}
observer.send(value: 2)
observer.send(value: 5)
observer.send(value: 4)
//要注意的是最后算出来的值直到输入的流完成后才会被发送出去。
observer.sendCompleted()
14.flatten
flatten 将一个事件流里的事件流变成一个单一的事件流。新的事件流的值按照指定的策略(FlattenStrategy)由内部的事件流的值组成。
被压平的值按照会变成外层的流的类型。比如:一个SignalProducers里的Signal,被flatten后的类型是SignalProducers。
15.合并
简单的说就是merge
按照时间顺序组成,concat
则是按照里面整个流顺序组合。latest
是只记录最近一次过来的值的那个流。
1 .merge
.Merge 策略将每个流的值立刻组合输出。无论内部还是外层的流如果收到失败就终止。
let (producerA, lettersObserver) = Signal.pipe()
let (producerB, numbersObserver) = Signal.pipe()
let (signal, observer) = Signal, NoError>.pipe()
signal.flatten(.merge).observeValues { (value) in
print("value: \(value)")
}
observer.send(value: producerA)
observer.send(value:producerB)
observer.sendCompleted()
lettersObserver.send(value:"a") // prints "a"
numbersObserver.send(value:"1") // prints "1"
lettersObserver.send(value:"b") // prints "b"
numbersObserver.send(value:"2") // prints "2"
lettersObserver.send(value:"c") // prints "c"
numbersObserver.send(value:"3") // prints "3"
2 .concet
Concat 策略是将内部的SignalProducer排序。外层的producer是马上被started。随后的producer直到前一个发送完成后才会start。一有失败立即传到外层。
let (signalA, lettersObserver) = Signal.pipe()
let (signalB, numberObserver) = Signal.pipe()
let (siganl, observer) = Signal, 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: 33) //不打印
lettersObserver.send(value: "sss")//sss
lettersObserver.send(value: "ffff")//ffff
lettersObserver.sendCompleted()
//要前一个信号执行完毕后,下一个信号才能被订阅
numberObserver.send(value: 44)// 44
3 .Latest
.latest只接收最新进来的那个流的值。
let (signalA, lettersObserver) = Signal.pipe()
let (signalB, numberObserver) = Signal.pipe()
let (siganl, observer) = Signal, 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: 33) //不打印
lettersObserver.send(value: "sss") //sss
observer.send(value: signalB)
//只接受最近进来的信号
numberObserver.send(value: 44) //44
lettersObserver.send(value: "ffff") // 不打印
16.flatMapError
flatMapError捕捉一个由SignalProducer产生的失败,然后产生一个新的SignalProducer代替。
let (signal, observer) = Signal.pipe()
let error = NSError.init(domain: "domian", code: 0, userInfo: nil)
signal.flatMapError { (value) -> SignalProducer in
return SignalProducer.init({ () -> String in
return "sssss"
})
}.observeValues { (value) in
print(value)
}
observer.send(value: 3333)
observer.send(value: 444)
observer.send(error: error)
17.retry
retry用于按照指定次数,在失败时重启SignalProducer。
var tries = 0
let limit = 2
let error = NSError.init(domain: "domian", code: 0, userInfo: nil)
let signal = SignalProducer.init { (observer, _) in
tries += 1
if tries < limit {
observer.send(error: error)
}else{
observer.send(value: "Success")
observer.sendCompleted()
}
}
// retry用于按照指定次数,在失败时重启SignalProducer。
signal.on(failed:{e in
print("Failure")
}).retry(upTo:3).start { (event) in
switch event {
case .completed:
print("Complete")
//判断输出值是否相等
case .value("Success"):
print("ddd")
case .interrupted:
print("interrupted")
case .failed(error):
print(error)
default:
break
}
}
18.continuousTextValues
usernameTextField.reactive就是把usernameTextField变成可响应的,而continuousTextValues就是text值的信号。
self.nameTF.reactive.continuousTextValues.observe { (value) in
print(value)
}
19.按钮点击事件和其他事件转信号
self.loginBtn.reactive.controlEvents(.touchUpInside).observe { (button) in
print("点击按钮")
}
20.属性的绑定
<~运算符是提供了几种不同的绑定属性的方式。注意这里绑定的属性必须是 MutablePropertyType类型的。
property <~ signal 将一个属性和信号绑定在一起,属性的值会根据信号送过来的值刷新。
property <~ producer 会启动这个producer,并且属性的值也会随着这个产生的信号送过来的值刷新。
property <~ otherProperty将一个属性和另一个属性绑定在一起,这样这个属性的值会随着源属性的值变化而变化。
var userName: MutableProperty = MutableProperty(nil)
var userPw : MutableProperty = MutableProperty(nil)
var logAction = Action { (input: Void) -> SignalProducer< Void , NoError> in
return SignalProducer{ (observer, disposable) in
observer.send(value: ())
observer.sendCompleted()
}
}
self.viewModel!.userName <~ nameTF.reactive.textValues
self.viewModel!.userPw <~ pwTF.reactive.textValues
loginBtn.reactive.pressed = CocoaAction((viewModel?.logAction)!)