Reactivecocoa 5.0 入门

文章出自此链接

最近再重新学习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<String, NoError>.init { (observer, _) in
       print("新的订阅,启动操作")
       observer.send(value: "Hello")
       observer.send(value: "World")
       observer.sendCompleted()
   }
   
   //创建观察者 (多个观察者观察会有副作用)
   let sub1 = Observer<String, NoError>(value: {
       print("观察者1接受信号\($0)")
   })
   
   let sub2 = Observer<String, NoError>(value: {
       print("观察者2接受信号\($0)")
   })
   //观察者订阅信号
   print("观察者1订阅信号")
   producer.start(sub1)
   print("观察者2订阅信号")
   producer.start(sub2)
    
}

2.热信号

func bindSignal2(){
   
   //2.热信号 (通过管道创建)
   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: 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<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()
   
}

5.信号联合

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

func bindSignal5(){
   //5.信号联合
   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: "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<String , NoError>.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<String, NoError>.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<Int, NoError>.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<Int, NoError>.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<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:"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<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: 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<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: 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<Any, NSError>.pipe()
let error = NSError.init(domain: "domian", code: 0, 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: 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<String, NSError >.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<String?> = MutableProperty<String?>(nil)
var userPw : MutableProperty<String?> = MutableProperty<String?>(nil)
var logAction = Action<Void, Void, NoError> { (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<UIButton>((viewModel?.logAction)!)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容

  • 什么是RAC? 几乎每一篇介绍RAC的文章开头都是这么一个问题。我这篇文章是写给新手(包括我自己)看的,所以这个问...
    ISwiftUI阅读 1,952评论 7 7
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,651评论 18 139
  • 标签: iOS RAC 概述 ReactiveCocoa是一个函数响应式编程框架,它能让我们脱离Cocoa AP...
    GodyZ阅读 7,529评论 16 97
  • 1.ReactiveCocoa常见操作方法介绍。 1.1 ReactiveCocoa操作须知 所有的信号(RACS...
    萌芽的冬天阅读 1,021评论 0 5
  • 前言由于时间的问题,暂且只更新这么多了,后续还会持续更新本文《最快让你上手ReactiveCocoa之进阶篇》,目...
    Karos_凯阅读 1,738评论 0 6