查看: 2145|回复: 0

[手机开发] ReactiveCocoa

发表于 2018-2-21 08:00:04
RAC类关系图:


RAC 信号源:


需要导入的头文件:
  1. 1 import ReactiveCocoa
  2. 2 import Result
  3. 3 import ReactiveSwift
复制代码

冷信号
  1. 1 //1.冷信号
  2. 2 let producer = SignalProducer<String, NoError>.init { (observer, _) in
  3. 3 print("新的订阅,启动操作")
  4. 4 observer.send(value: "Hello")
  5. 5 observer.send(value: "World")
  6. 6 observer.sendCompleted()
  7. 7 }
  8. 8
  9. 9 //创建观察者 (多个观察者观察会有副作用)
  10. 10 let sub1 = Signal<String, NoError>.Observer(value: { (value) in
  11. 11 print("观察者1接受信号\(value)")
  12. 12 })
  13. 13
  14. 14 let sub2 = Signal<String, NoError>.Observer(value: { (value) in
  15. 15 print("观察者2接受信号\(value)")
  16. 16 })
  17. 17 //观察者订阅信号
  18. 18 print("观察者1订阅信号")
  19. 19 producer.start(sub1)
  20. 20 print("观察者2订阅信号")
  21. 21 producer.start(sub2)
复制代码

结果:


热信号
  1. 1 // 热信号 (通过管道创建)
  2. 2 let (signalA, observerA) = Signal<String, NoError>.pipe()
  3. 3 let (signalB, observerB) = Signal<Int, NoError>.pipe()
  4. 4
  5. 5 Signal.combineLatest(signalA,signalB).observeValues { (value) in
  6. 6 print("两个热信号收到的值\(value.0) + \(value.1)")
  7. 7 }
  8. 8 //订阅信号要在send之前
  9. 9 signalA.observeValues { (value) in
  10. 10 print("signalA : \(value)")
  11. 11 }
  12. 12
  13. 13 observerA.send(value: "sssss")
  14. 14 // observerA.sendCompleted()
  15. 15 observerB.send(value: 2)
  16. 16 // observerB.sendCompleted()
  17. 17
  18. 18 observerB.send(value: 100)
  19. 19 //不sendCompleted和sendError 热信号一直激活
  20. 20 // observerB.sendCompleted()
复制代码

结果:


文本框监听
  1. 1 func racsTest() {
  2. 2 textField.reactive.continuousTextValues.observeValues { (text) in
  3. 3
  4. 4 print("值为:\(text ?? "")")
  5. 5
  6. 6 }
  7. 7 }
复制代码

结果:


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

方法一:

  1. textField.reactive.continuousTextValues.map { (text) -> Int in
  2. return (text?.count)!//!.characters.count
  3. }.observeValues { (count) in
  4. print("数值为:\(count)")
  5. }
复制代码

输入: Hello123

结果为:

方法二:

  1. 1 let (signal, observer) = Signal<String, NoError>.pipe()
  2. 2 signal.map { (string) -> Int in
  3. 3 return string.lengthOfBytes(using: .utf8)
  4. 4 }.observeValues { (length) in
  5. 5 print("长度length: \(length)")
  6. 6 }
  7. 7
  8. 8 observer.send(value: "123456")
  9. 9
  10. 10 observer.send(value: "some")
复制代码

结果为:


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

方法一:

  1. 1 textField.reactive.continuousTextValues.filter { (text) -> Bool in
  2. 2
  3. 3 return text!.characters.count > 3
  4. 4
  5. 5 }.observeValues { (text) in
  6. 6
  7. 7 print(text ?? "")
  8. 8
  9. 9 }
复制代码

输入: 1234

结果:

1234

方法二:

  1. 1 let (signal, observer) = Signal<Int, NoError>.pipe()
  2. 2 signal.filter { (value) -> Bool in
  3. 3 return value % 2 == 0
  4. 4 }.observeValues { (value) in
  5. 5 print("\(value)能被2整除")
  6. 6 }
  7. 7 observer.send(value: 3)
  8. 8 observer.send(value: 4)
  9. 9 observer.send(value: 6)
  10. 10 observer.send(value: 7)
复制代码

结果:

4能被2整除

6能被2整除


信号合并

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

  1. 1 // 信号合并 两个要被订阅combineLatest 才能被订阅,被订阅后,合并中其中一个sendNext都会激活订阅
  2. 2 let (signalA, observerA) = Signal<String, NoError>.pipe()
  3. 3 let (signalB, observerB) = Signal<Array<Any> , NoError>.pipe()
  4. 4 Signal.combineLatest(signalA, signalB).observeValues { (value) in
  5. 5 print("合并的信号:\(value)")
  6. 6 }
  7. 7
  8. 8 observerA.send(value: "xxx")
  9. 9 observerA.sendCompleted()
  10. 10 observerB.send(value: ["sdsd","ddddd"])
  11. 11 observerB.sendCompleted()
复制代码

结果:


信号联合

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

  1. 1 // 信号联合
  2. 2 let (signalA, observerA) = Signal<String, NoError>.pipe()
  3. 3 let (signalB, observerB) = Signal<String, NoError>.pipe()
  4. 4
  5. 5 //两个到需要订阅 才激活zip
  6. 6 Signal.zip(signalA, signalB).observeValues { (value) in
  7. 7 print("zip: \(value)")
  8. 8 }
  9. 9
  10. 10 observerA.send(value: "1")
  11. 11 // observerA.sendCompleted()
  12. 12 observerB.send(value: "2")
  13. 13 // observerB.sendCompleted()
  14. 14 observerB.send(value: "cc")
  15. 15 observerA.send(value: "dd")
复制代码

结果:


调度器
  1. 1 QueueScheduler.main.schedule(after: Date.init(timeIntervalSinceNow: 3)) {
  2. 2 print("主线程3秒过去了")
  3. 3 }
  4. 4 QueueScheduler.init().schedule(after: Date.init(timeIntervalSinceNow: 2)) {
  5. 5 print("子线程2秒过去了")
  6. 6 }
复制代码

结果:


通知
  1. 1 // 通知
  2. 2 NotificationCenter.default.reactive.notifications(forName: Notification.Name(rawValue: "UIKeyboardWillShowNotification"), object: nil).observeValues { (notification) in
  3. 3 print("键盘弹起")
  4. 4 }
  5. 5
  6. 6 NotificationCenter.default.reactive.notifications(forName: Notification.Name(rawValue:"UIKeyboardWillHideNotification"), object: nil).observeValues { (notification) in
  7. 7 print("键盘收起")
  8. 8 }
复制代码

结果:


KVO
  1. 1 let result = self.textField.reactive.producer(forKeyPath: "text")
  2. 2 result.start { (text) in
  3. 3 print("----------->\(text)");
  4. 4 }
复制代码

输入:Hello

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

结果:


迭代器
  1. 1 // 迭代器
  2. 2 let array:[String] = ["name1", "name2"]
  3. 3 var arrayIterator = array.makeIterator()
  4. 4 while let temp = arrayIterator.next() {
  5. 5 print(temp)
  6. 6 }
  7. 7
  8. 8 //swift系统自带
  9. 9 array.forEach { (value) in
  10. 10 print("系统自带:\(value)")
  11. 11 }
复制代码

结果:


on

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

  1. 1 let signal = SignalProducer<String , NoError>.init { (obsever, _) in
  2. 2 obsever.send(value: "SignalProducer")
  3. 3 obsever.sendCompleted()
  4. 4 }
  5. 5
  6. 6 //可以通过 on来观察signal,生成一个新的信号,即使没有订阅者(sp.start())也会被触发。
  7. 7 let sp = signal.on(starting: {
  8. 8 print("开始")
  9. 9 }, started: {
  10. 10 print("结束")
  11. 11 }, event: { (event) in
  12. 12 print("Event: \(event)")
  13. 13 }, failed: { (error) in
  14. 14 print("error: \(error)")
  15. 15 }, completed: {
  16. 16 print("信号完成")
  17. 17 }, interrupted: {
  18. 18 print("信号被中断")
  19. 19 }, terminated: {
  20. 20 print("信号结束")
  21. 21 }, disposed: {
  22. 22 print("信号清理")
  23. 23 }) { (value) in
  24. 24 print("value: \(value)")
  25. 25 }
  26. 26
  27. 27 sp.start()
复制代码

结果:


reduce

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

  1. 1 let (signal, observer) = Signal<Int, NoError>.pipe()
  2. 2 //reduce后的是聚合的次数
  3. 3 signal.reduce(3) { (a, b) -> Int in
  4. 4 //a是相乘后的值 b是传入值
  5. 5 print("a:\(a) b:\(b)")
  6. 6 return a * b
  7. 7 }.observeValues { (value) in
  8. 8 print("输出的值是:\(value)")
  9. 9 }
  10. 10
  11. 11 observer.send(value: 2)
  12. 12 observer.send(value: 5)
  13. 13 observer.send(value: 4)
  14. 14 //要注意的是最后算出来的值直到输入的流完成后才会被发送出去。
  15. 15 observer.sendCompleted()
复制代码

结果:


flatten

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


合并

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

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

  1. 1 let (producerA, lettersObserver) = Signal<String, NoError>.pipe()
  2. 2 let (producerB, numbersObserver) = Signal<String, NoError>.pipe()
  3. 3 let (signal, observer) = Signal<Signal<String, NoError>, NoError>.pipe()
  4. 4 signal.flatten(.merge).observeValues { (value) in
  5. 5 print("value: \(value)")
  6. 6 }
  7. 7 observer.send(value: producerA)
  8. 8 observer.send(value:producerB)
  9. 9 observer.sendCompleted()
  10. 10 lettersObserver.send(value:"埃及") // prints "a"
  11. 11 numbersObserver.send(value:"1") // prints "1"
  12. 12 lettersObserver.send(value:"罗马") // prints "b"
  13. 13 numbersObserver.send(value:"2") // prints "2"
  14. 14 lettersObserver.send(value:"瑞典") // prints "c"
  15. 15 numbersObserver.send(value:"3") // prints "3"<img id="uploading_image_6184" src="http://img.it-home.org/data/attachment/forum/2018pic/loading.gif" alt=""><img id="uploading_image_34514" src="http://img.it-home.org/data/attachment/forum/2018pic/loading.gif" alt="">
复制代码

结果:


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

  1. 1 let (signalA, lettersObserver) = Signal<Any, NoError>.pipe()
  2. 2 let (signalB, numberObserver) = Signal<Any, NoError>.pipe()
  3. 3
  4. 4 let (siganl, observer) = Signal<Signal<Any, NoError>, NoError>.pipe()
  5. 5
  6. 6 siganl.flatten(.concat).observeValues { (value) in
  7. 7 print("value: \(value)")
  8. 8 }
  9. 9 observer.send(value: signalA)
  10. 10 observer.send(value: signalB)
  11. 11 observer.sendCompleted()
  12. 12
  13. 13 lettersObserver.send(value: "dddd")//dddd
  14. 14 numberObserver.send(value: 33) //不打印是因为lettersObserver的发送值没有结束,所以 44 能打印出来
  15. 15
  16. 16 lettersObserver.send(value: "sss")//sss
  17. 17 lettersObserver.send(value: "ffff")//ffff
  18. 18 lettersObserver.sendCompleted()
  19. 19 //要前一个信号执行完毕后,下一个信号才能被订阅
  20. 20 numberObserver.send(value: 44)// 44
复制代码

结果:

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

  1. 1 let (signalA, lettersObserver) = Signal<Any, NoError>.pipe()
  2. 2 let (signalB, numberObserver) = Signal<Any, NoError>.pipe()
  3. 3
  4. 4 let (siganl, observer) = Signal<Signal<Any, NoError>, NoError>.pipe()
  5. 5
  6. 6 siganl.flatten(.latest).observeValues { (value) in
  7. 7 print("value: \(value)")
  8. 8 }
  9. 9 observer.send(value: signalA)
  10. 10 // observer.send(value: signalB)
  11. 11
  12. 12 lettersObserver.send(value: "dddd") //dddd
  13. 13 numberObserver.send(value: 33) //不打印
  14. 14 lettersObserver.send(value: "sss") //sss
  15. 15 observer.send(value: signalB)
  16. 16 //只接受最近进来的信号
  17. 17 numberObserver.send(value: 44) //44
  18. 18 lettersObserver.send(value: "ffff") // 不打印
复制代码

结果:


flatMapError

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

  1. 1 let (signal, observer) = Signal<Any, NSError>.pipe()
  2. 2 let error = NSError.init(domain: "domian", code: 0, userInfo: nil)
  3. 3 signal.flatMapError { (value) -> SignalProducer<Any, NoError> in
  4. 4 return SignalProducer<Any, NoError>.init({ () -> String in
  5. 5 return "sssss"
  6. 6 })
  7. 7 }.observeValues { (value) in
  8. 8 print(value)
  9. 9 }
  10. 10
  11. 11 observer.send(value: "无双")
  12. 12 observer.send(value: "鹰眼")
  13. 13 observer.send(error: error)
复制代码

结果:


retry

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

  1. 1 var tries = 0
  2. 2 let limit = 2
  3. 3 let error = NSError.init(domain: "??我错了,求放过!", code: 0, userInfo: nil)
  4. 4
  5. 5 let signal = SignalProducer<String, NSError >.init { (observer, _) in
  6. 6 tries += 1
  7. 7 if tries < limit {
  8. 8 observer.send(error: error)
  9. 9 }else{
  10. 10 observer.send(value: "Success")
  11. 11 observer.sendCompleted()
  12. 12 }
  13. 13 }
  14. 14
  15. 15 // retry用于按照指定次数,在失败时重启SignalProducer。
  16. 16 signal.on(failed:{e in
  17. 17 print("Failure")
  18. 18 }).retry(upTo:3).start { (event) in
  19. 19 switch event {
  20. 20 case .completed:
  21. 21 print("Complete")
  22. 22 //判断输出值是否相等
  23. 23 case .value("Success"):
  24. 24 print("ddd")
  25. 25 case .interrupted:
  26. 26 print("interrupted")
  27. 27 case .failed(error):
  28. 28 print(error)
  29. 29 default:
  30. 30 break
  31. 31
  32. 32 }
  33. 33 }
复制代码

结果:


continuousTextValues

usernameTextField.reactive就是把usernameTextField变成可响应的,而continuousTextValues就是text值的信号。

  1. 1 self.nameTF.reactive.continuousTextValues.observe { (value) in
  2. 2 print(value)
  3. 3 }
复制代码

结果:


按钮点击事件和其他事件转信号
  1. 1 self.loginBtn.reactive.controlEvents(.touchUpInside).observe { (button) in
  2. 2 print("点击按钮")
  3. 3 }
复制代码

结果:


属性的绑定

<~运算符是提供了几种不同的绑定属性的方式。注意这里绑定的属性必须是 MutablePropertyType类型的。

property <~ signal 将一个属性和信号绑定在一起,属性的值会根据信号送过来的值刷新。
property <~ producer 会启动这个producer,并且属性的值也会随着这个产生的信号送过来的值刷新。
property <~ otherProperty将一个属性和另一个属性绑定在一起,这样这个属性的值会随着源属性的值变化而变化。

  1. 1 var userName: MutableProperty<String?> = MutableProperty<String?>(nil)
  2. 2 var userPw : MutableProperty<String?> = MutableProperty<String?>(nil)
  3. 3 var logAction = Action<Void, Void, NoError> { (input: Void) -> SignalProducer< Void , NoError> in
  4. 4 return SignalProducer{ (observer, disposable) in
  5. 5 observer.send(value: ())
  6. 6 observer.sendCompleted()
  7. 7 }
  8. 8 }
复制代码

  1. self.viewModel!.userName <~ nameTF.reactive.textValues
  2. self.viewModel!.userPw <~ pwTF.reactive.textValues
  3. loginBtn.reactive.pressed = CocoaAction<UIButton>((viewModel?.logAction)!)<br>
复制代码

demo

  1. 1 // <>里面可以是任意类型,它代表属性的类型。
  2. 2 let racValue = MutableProperty<Int>(1)
  3. 3
  4. 4 racValue.producer.startWithValues { (make) in
  5. 5 print(make)
  6. 6 }
  7. 7
  8. 8 racValue.value = 10
复制代码

结果:


方法调用拦截

当你想获取到某个方法被调用的事件,比如UIViewController的ViewwillAppear事件

  1. 1 func racsTest() {
  2. 2 self.reactive.trigger(for: #selector(UIViewController.viewWillAppear(_:))).observeValues { () in
  3. 3
  4. 4 print("viewWillAppear被调用了")
  5. 5
  6. 6 }
  7. 7
  8. 8 }
  9. 9
  10. 10 override func viewWillAppear(_ animated: Bool) {
  11. 11 print("------------------------------>>>>")
  12. 12 }
复制代码

结果:


SignalProducer

SignalProducer:信号发生器,可以产生多个信号,并且可以用在操作(operation)和任务(task)中,比如网络请求,并且每次调用start()函数将会创建一个基本的操作(operation),确保信号接收者能收到信号。

上述代码可以变更为,调用start函数,触发相应的操作。其触发函数,只能调用start

  1. 1 let userSignal = textField.reactive.continuousTextValues.map { (str) -> Bool in
  2. 2 print("userSignal:\(str?.count ?? 0)")
  3. 3 return str!.count == 6
  4. 4 }
  5. 5 let passSignal = pasField.reactive.continuousTextValues.map { (str) -> Bool in
  6. 6 print("passSignal:\(str?.count ?? 0)")
  7. 7 return str!.count == 6
  8. 8 }
  9. 9
  10. 10 userSignal.combineLatest(with: passSignal).map { $0 && $1 }.map { (value) -> String in
  11. 11 print("--->value:\(value)")
  12. 12 return value ? "UIColor.green" : "UIColor.lightGray"
  13. 13 }.producer.start { (signal) in
  14. 14 print("信号的值是:\(signal.event.value ?? "")")
  15. 15 }
复制代码
[code][/code]

结果:



回复

使用道具 举报