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閱讀 229,963評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,348評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,083評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,706評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,442評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,802評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,983評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,542評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,287評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,486評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,710評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,116評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,412評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,224評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,462評論 2 378

推薦閱讀更多精彩內容

  • 什么是RAC? 幾乎每一篇介紹RAC的文章開頭都是這么一個問題。我這篇文章是寫給新手(包括我自己)看的,所以這個問...
    ISwiftUI閱讀 1,961評論 7 7
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,825評論 18 139
  • 標簽: iOS RAC 概述 ReactiveCocoa是一個函數響應式編程框架,它能讓我們脫離Cocoa AP...
    GodyZ閱讀 7,565評論 16 97
  • 1.ReactiveCocoa常見操作方法介紹。 1.1 ReactiveCocoa操作須知 所有的信號(RACS...
    萌芽的冬天閱讀 1,034評論 0 5
  • 前言由于時間的問題,暫且只更新這么多了,后續還會持續更新本文《最快讓你上手ReactiveCocoa之進階篇》,目...
    Karos_凱閱讀 1,751評論 0 6