RxSwift學習--核心邏輯初探

前言

寫這篇文章是爲了記錄下本身在對於RxSwift的學習過程當中的概念理解,操做步驟以及心得體會,以便於在之後複習所用。若是文中有任何錯誤的地方,還請各位看官老爺們指正...(先捂上臉🤦)html

函數響應式編程

在學習RxSwift以前,先來了解一下函數響應式編程的思想,咱們能夠把函數響應式編程拆開來看,分爲函數式編程和響應式編程來理解:react

1.函數式編程

函數式編程簡稱FP(Functional Programming),函數式編程就是一種抽象程度很高的編程範式,它將計算機運算看作是數學中函數的計算,而純粹的函數式編程語言編寫的函數沒有變量,所以,任意一個函數,只要輸入是肯定的,輸出就是肯定的,這種純函數咱們稱之爲沒有反作用。而容許使用變量的程序設計語言,因爲函數內部的變量狀態不肯定,一樣的輸入,可能獲得不一樣的輸出,所以,這種函數是有反作用的。git

函數式編程的一個特色就是:容許把函數自己做爲參數傳入另外一個函數,同時還容許返回一個函數!github

函數表達式: y = f(x) ---> x = f(x) ---> y = f(f(x))編程

下面寫一個栗子🌰來理解一下: 有這樣一個需求:對於數組[1,2,3,4,5,6,7],首先獲取 > 3的數字,獲取到的數字以後 + 1,再輸出全部數字中的偶數swift

let array = [1,2,3,4,5,6,7]
for num in array{
            if num > 3{
                let number = num + 1
                if (number % 2 == 0) {
                    print(number)
                  }
            }
        }
複製代碼

這裏咱們利用行爲式思路解決了這個需求,下面來換個思路來解決,使用 Arrayfilter方法;數組

let array = [1,2,3,4,5,6,7]
 array.filter{ $0 > 3}
            .filter{ ($0+1) % 2 == 0 }
            .forEach { print($0) }
複製代碼

這裏 array.filter 函數接受一個閉包類型的參數,filter方法會對 array 中的每個元素都用傳入filter 的閉包調用一遍,根據這個閉包的返回值決定是否將這個元素做爲符合條件的元素加入咱們的查找結果中。xcode

簡單來講咱們只須要在傳入的閉包中聲明好查找的規則,這樣咱們就完成整個查找操做的處理了。咱們這裏並無告訴程序應該怎麼去查找知足條件的元素的方法,而只是聲明瞭一個規則。這樣作最大的好處就是可以減小咱們的代碼量,讓咱們的代碼看起來很是的簡潔,並且易理解。 這種方式就是函數式編程的一個例子。bash

2.響應式編程

響應式編程簡稱RP(Reactive Programming),響應式編程是一種面向數據流和變化傳播的異步編程範式。這意味着能夠在編程語言中很方便地表達靜態或動態的數據流,而相關的計算模型會自動將變化的值經過數據流進行傳播。閉包

簡單的來講就是基於事件流的編程方式。事件流就是將要發生事件按照時間順序排序發生造成的。而當這個事件流產生了返回的數據,能夠馬上獲得通知並調用回調函數去處理數據。(在現實生活中就是:我在家拿起手機預訂了一份外賣,而後商家會收到訂單,開始製做外賣,製做完成後會通知騎手取餐,騎手接單取餐,而後送餐,到達目的地,外賣送達,訂單完成,這樣一系列的事件,先稱它爲事件流,若是在這些事件流進行的過程當中,好比說商家沒有出餐,或者騎手沒有取餐等等,這些都會致使這個事件流沒法完成,而咱們能夠根據這個事件流中的任何一個事件的結果來進行響應)

從這個小例子能夠看到組成響應式編程的三種動做(數據):事件(數據),錯誤,結束。經過獲得這三個響應式動做,咱們就能夠在程序中做出不一樣的響應。

這裏我的以爲有點很重要,就是要對事件進行「預訂/監聽」,而後才能收到這個事件的反饋。而對於我而言,我就是監聽事件的人,也就是「觀察者/訂閱方」,監聽+觀察者是否是就是咱們比較熟悉的觀察者模式,那麼響應式編程就是觀察者模式+事件流的控制。

3.函數響應式編程

函數響應式編程 FRP(Functional Reactive Programming)是函數式編程與響應式編程相結合起來的,響應式編程思想爲體, 函數式編程思想爲用。(比較經典的框架就是RAC和RxSwift),經常有人說,FRP能讓你的代碼像數學同樣簡潔,業務像流水同樣清晰流暢。

函數響應式

RxSwift初識

1.RxSwift簡介

首先,ReactiveX(簡寫: Rx) 是一個能夠幫助咱們簡化異步編程的框架,簡單來講就是基於異步 Event序列的響應式編程,並提供更優雅的數據綁定,能夠時刻響應新的數據同時順序地處理它們。RxSwift (ReactiveX for Swift),就是ReactiveXSwift版本 ReactiveX家族很是強大,就如同‘毒液家族’同樣的強大,除了我後面會學習的 RxSwift 以外,還有 RAC(ReactiveCocoa), RxJava, RxJS, RxKotlin, Rx.NET...等等.

2.RxSwift導入配置

(1) 手動導入

  • RxSwift GitHub 上下載最新的代碼,
  • 將下載下來的源碼包中 Rx.xcodeproj 拖拽至工程中,
  • Project -> Targets -> General -> Embedded Binaries 配置項, RxSwift.frameworkRxCocoa.framework 添加進來便可
  • 在須要使用 RxSwift的地方import 進來

(2) CocoaPods導入

# Podfile
use_frameworks!
target 'YOUR_TARGET_NAME' do
    pod 'RxSwift', '~> 5.0'
    pod 'RxCocoa', '~> 5.0'
end
複製代碼

替換 YOUR_TARGET_NAME 而後在 Podfile 目錄下, 終端輸入:

$ pod install
複製代碼

🗣🗣🗣這裏說明一下爲何會導入RxSwiftRxCocoa兩個庫,它們的做用分別是:

  • RxSwift:它只是基於 Swift 語言的 Rx 標準實現接口庫,因此 RxSwift 裏不包含任何Cocoa或者 UI方面的類。
  • RxCocoa:是基於 RxSwift 針對於 iOS 開發的一個庫,它經過 Extension 的方法給原生的好比 UI 控件添加了 Rx的特性,使得咱們更容易訂閱和響應這些控件的事件。

3.RxSwift特性

  • 複合 -Rx 就是和複合的代名詞
  • 複用 - 複用性比較強 - 代碼量下降
  • 清晰 - 由於聲明都是不可變更,代碼函數式編程可讀性強
  • 易用 - 理解容易,還抽象的了異步編程,統一代碼風格
  • 穩定 - 由於 Rx 是徹底經過單元測試的
  • 裝X - 代碼的風格很明顯比原⽣好

到底是不是這樣的呢,下面經過一些經常使用的方式來驗證一下:

(1)KVO

通常寫法:
func setupKVO() {
    self.person.addObserver(self, forKeyPath: "name", options: .new, context: nil)
}
    
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    person.name = "\(person.name) +"
    // print(person.name)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    print("響應")
    print(change as Any)
}

deinit {
    self.removeObserver(self.person, forKeyPath: "name", context: nil)
}
複製代碼
RxSwift寫法:
func setupKVO() {
    self.person.rx.observeWeakly(String.self, "name")
        .subscribe(onNext: { (value) in
            print(value as Any)
        })
        .disposed(by: disposeBag)
}
    
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    person.name = "\(person.name) +"
    // print(person.name)
}
複製代碼

是否是感受RxSwift版本的KVO寫的代碼更少了,並且也不用去實現觀察者的代理方法,不用關心是否遺漏removeObserver方法。

(2)Target Action

通常寫法:
func setupButton() {
   button.addTarget(self, action: #selector(didClickButton), for: .touchUpInside)
}

@objc func didClickButton(){
    print("點我幹什麼")
}
複製代碼
RxSwift寫法:
func setupButton() {
    self.button.rx.tap
      .subscribe(onNext: { () in
            print("點擊事件")
        })
      .disposed(by: disposeBag)
}
複製代碼

不須要實現Target Action,代碼更加簡單了

(3)代理

通常寫法:
class ViewController: UIViewController {
    ...
    override func viewDidLoad() {
        super.viewDidLoad()
        scrollView.delegate = self
    }
}

extension ViewController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        print("contentOffset: \(scrollView.contentOffset)")
    }
}
複製代碼
RxSwift寫法:
class ViewController: UIViewController {
    ...
    override func viewDidLoad() {
        super.viewDidLoad()

        scrollView.rx.contentOffset
            .subscribe(onNext: { contentOffset in
                print("contentOffset: \(contentOffset)")
            })
            .disposed(by: disposeBag)
    }
}
複製代碼

不須要實現代理方法啦,能夠直接獲取到scrollview的偏移

(4)通知

通常寫法:
var testObserver: NSObjectProtocol!

override func viewDidLoad() {
    super.viewDidLoad()

    testObserver = NotificationCenter.default.addObserver(
          forName: .UIApplicationWillEnterForeground,
          object: nil, queue: nil) { (notification) in
        print("Application Will Enter Foreground")
    }
}

deinit {
    NotificationCenter.default.removeObserver(testObserver)
}
複製代碼
RxSwift寫法:
override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.rx
        .notification(.UIApplicationWillEnterForeground)
        .subscribe(onNext: { (notification) in
            print("Application Will Enter Foreground")
        })
        .disposed(by: disposeBag)
}
複製代碼

不須要去關注是否已經移除了通知,不會由於沒有移除通知而出現崩潰

(5)單擊手勢

通常寫法:
func setupGestureRecognizer(){
    let tap = UITapGestureRecognizer()
    tap.addTarget(self, action: #selector(singleTap(_:)))
    self.label.addGestureRecognizer(tap)
    self.label.isUserInteractionEnabled = true
    
}
    
@objc func singleTap(_ tapGesture: UITapGestureRecognizer) {
    print("點我幹嗎")
}
複製代碼
RxSwift寫法:
func setupGestureRecognizer(){
        
    let tap = UITapGestureRecognizer()
    self.label.addGestureRecognizer(tap)
    self.label.isUserInteractionEnabled = true
    tap.rx.event.subscribe(onNext: { (tap) in
        print(tap.view)
    })
    .disposed(by: disposeBag)
  }
複製代碼

少寫了手勢觸發實現的方法,代碼更簡介了

(6)Timer定時器

通常寫法:
var testtimer = Timer()

func setupTimer() {
    testtimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(UpdateTimer), userInfo: nil, repeats: true)
    testtimer.fire();
    RunLoop.current.add(testtimer, forMode: .common)
}

@objc func UpdateTimer() {

   print("timer start")
    
}
複製代碼
RxSwift寫法:
var timer: Observable<Int>!

func setupTimer() {
    timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
    timer.subscribe(onNext: { (num) in
        print(num)
    })
    .disposed(by: disposeBag)
}

複製代碼

這裏timer更好地是不用考慮頁面上的Scrollviewtimer的影響

看完這些小例子🌰以後,以爲RxSwift比通常的Swift寫法要簡單好多,簡直就是「騷通常的操做」。

4.RxSwift核心邏輯初識

在前面的概念介紹中大概已經知道了ReactiveX是基於異步 Event序列的響應式編程, 並提供更優雅的數據綁定,能夠時刻響應新的數據同時順序地處理它們,既然要響應數據,就還須要一個觀察者。

RxSwift 核心概念就能夠理解爲一個觀察者(Observer)訂閱一個可被觀察序列(Observable)。觀察者對可被觀察序列發射的事件(Event)或事件序列做出響應。

先來理解一下這三個類的概念:

  • Observable<T> 這個類就是 Rx 框架的基礎,咱們能夠稱它爲可觀察序列。它的做用就是能夠異步地產生一系列的 Event(事件),即一個 Observable<T> 對象會隨着時間推移不按期地發出 event(element : T) 這樣一個東西。
  • 並且這些 Event 還能夠攜帶數據,它的泛型 <T> 就是用來指定這個 Event 攜帶的數據的類型。
  • 有了可觀察序列,咱們還須要有一個 Observer(訂閱者)來訂閱它,這樣這個訂閱者才能收到 Observable<T> 不時發出的 Event

既然Observable是一個可被觀察的序列,能夠異步地產生一系列的 Event,那麼查看RxSwift/Event.swift 源碼能夠發現

public enum Event<Element> {
    /// Next element is produced.
    case next(Element)

    /// Sequence terminated with an error.
    case error(Swift.Error)

    /// Sequence completed successfully.
    case completed
}
複製代碼

Event被定義成一個枚舉值,這也就是說一個Observable可觀察序列能夠發出三種不一樣類型的Event事件:

  • nextnext 事件就是那個能夠攜帶數據 <T> 的事件,能夠說它就是一個普通事件

  • errorerror 事件表示一個錯誤,它能夠攜帶具體的錯誤內容,一旦 Observable 發出了 error event,則這個Observable就等於終止了,之後它不再會發出event` 事件了。

  • completedcompleted事件表示 Observable 發出的事件正常地結束了,跟 error 同樣,一旦 Observable 發出了 completed event,則這個 Observable 就等於終止了,之後它不再會發出 event 事件了

序列監聽有三個步驟:1.建立序列,2訂閱序列,3.發送信號。當建立序列,並訂閱了序列後,只要某個事件發送了序列消息,就能夠在序列訂閱的閉包裏面監聽到發送的消息。

下面建立一個可觀察序列來感覺一下:

//第一步:建立序列
//在create()函數中傳入一個閉包,任務是對每個過來的訂閱進行處理
 let ob = Observable<Any>.create { (observer) -> Disposable in
            // 第三步:發送信號(onCompleted和onError只能發送一個)
            observer.onNext("你好啊")
            observer.onCompleted()
//            observer.onError(NSError.init(domain: "loser", code: 10010, userInfo: nil))
            return Disposables.create()
 
//第二步:訂閱信息
//當咱們訂閱了Observable的消息後,只要Observable的事件觸發,都會經過onNext這個閉包告訴咱們。
 let _ = ob.subscribe(onNext: { (text) in
            print("訂閱到:\(text)")    //這裏會監聽到訂閱的Observable事件
        }, onError: { (error) in
            print("error: \(error)")    //當發生錯誤時,會回調這裏
        }, onCompleted: { // 當序列執行完畢時,會回調這裏。
            print("完成")
        }) {
            print("銷燬") 
        }
        .disposed(by: disposeBag)
複製代碼

DisposeBag:做用是 Rx 在視圖控制器或者其持有者將要銷燬的時候,自動釋法掉綁定在它上面的資源。它是經過相似「訂閱處置機制」方式實現(相似於 NotificationCenterremoveObserver)。

總結

這就算是RxSwift響應式的核心邏輯了,這裏有點疑惑就是:爲何觀察者發出的信號,可觀察序列可以訂閱到呢?

未完待續...... RxSwift學習--核心邏輯再探

注:感謝下面的參考文檔

RxSwift 中文文檔

航歌Swift

相關文章
相關標籤/搜索