mojito: 麻煩給個人愛人來一份 RxSwift

學過 Swift 的 同窗都知道, RxSwift 宛如 周董的 mojitogit

開始微醺github

再者上頭編程

爲何要學習 RxSwift ?json

卡蜜爾說過api

優雅,永不過期數組


麻煩給個人愛人來一份 RxSwift

RxSwift 是 Rx 系列的 Swift 版本,相較於 OC 版的 ReactiveCocoa安全

它們有着殊途同歸之妙 函數響應式編程(FRP)bash

什麼是 函數響應式編程 ?markdown


函數式:

函數式編程的核心思想是 stateless,無狀態。函數自己並不關心外界輸入的值網絡

它只是在函數內部,將輸入的值 和 輸出的值 完成一種映射,即 input => output

好比:

func changeNum(input: Int) -> Int {
    return input * 3
}

// changeNum 並不會對input 產生改變,只是將運算以後的值 輸出
複製代碼

無狀態 意味着函數自己,不會改變外部的狀態,也不會改變輸入的值的狀態


再好比

Q:將數組 [1,2,3,4] 裏的元素 都乘以2,返回新的數組

那麼通常的作法多是:

命令式編程

let array = [1,2,3,4]
var newArray: [Int] = []

for item in array {
    var num = item
    num *= 2
    newArray.append(num)
} 
// [2,4,6,8]
複製代碼

命令式編程傾向於怎麼作,具體是怎麼把每一個數都 * 2 的,那麼這裏 涉及到了 可變數組 newArray

若是某一個時刻,newArray 被某個地方改變了,都會達到 非預期的效果


那麼函數式編程會怎麼作呢?

let array = [1,2,3,4]

let newArray = array.compactMap {
    return $0 * 2
}
// [2,4,6,8]
複製代碼

函數式編程申明式編程的 思想大致一致

它們都只關注 作什麼,而不是上面的 怎麼作?


函數式編程:傾向於作什麼,省去其繁瑣的過程,一種更爲 安全,直觀,易懂的編程方式


響應式:

一種抽象的事件流異步編程方法

好比:用戶點擊一個按鈕,發送網絡請求,並將結果展現在label 上

這裏網絡請求是異步

想要展現在label 上,就要拿到 網絡請求的回調,進一步展現

造成事件流寫法就是


button.rx.tap.subscribe(onNext: {              // 點擊按鈕
    HomeApi.getTitle().asObservable() // 發起網絡請求
    .map { (title) -> String in       // 拿到回調進行 map
    ("我是 \(title)")
    } 
    .bind(to: (titleLabel?.rx.text)!) // 綁定給 label
    .disposed(by: rx.disposeBag)      // 管理生命週期
})
複製代碼

這麼一個較爲複雜的操做,且包含異步操做的流程

在 RxSwift 的 調整以後,是否是更爲 簡單易懂 ? 事件的分發以及維護,能夠在一個地方完成

大大提升了 代碼的可讀性,以及維護成本

整個事件流的過程 以下:

咱們不用去關心 序列中的 每個元素,是異步的 仍是同步的,線程是否安全

只有當咱們點擊按鈕發送信號 以後 ,代碼塊內的函數體纔會執行,整個一系列的事件流纔會產生

這使得咱們更加面向業務邏輯

而不是每一步的具體操做


那麼具體 RxSwift 是怎麼作到的呢?

喝完 mojito 你就知道了


我喜歡閱讀它時緊皺的眉頭

對於初學者來講

RxSwift 的學習曲線確實很陡,它詮釋了什麼是面向協議編程

過程雖然晦澀

但道阻且長

真正的大師永遠懷着一顆學徒的心


rx

在RxSwift 的世界裏,萬物皆 rx,處處是 序列(sequence)

聽着像不像 iOS 的萬物皆對象

是的沒錯,咱們來看一下rx Reactive 的定義,首先引入眼簾的是 一個 叫 ReactiveCompatible 的協議

public protocol ReactiveCompatible {
    # 關聯協議
    associatedtype ReactiveBase 

    # rx 是 Reactive 類型,並將 ReactiveBase 傳入
    static var rx: Reactive<ReactiveBase>.Type { get set }

    var rx: Reactive<ReactiveBase> { get set }
}
複製代碼

Reactive 中 還對 ReactiveCompatible進行了 協議的拓展,在這個擴展中,經過調用rx,返回的是

Reactive 類型 或者Reactive實例

extension ReactiveCompatible {
    # Reactive 類型
    public static var rx: Reactive<Self>.Type {
        get {  return Reactive<Self>.self }
    }
    # Reactive 實例
    public var rx: Reactive<Self> {
        get {  return Reactive(self) }
    }
}
複製代碼

在看一下 Reactive 的 實現,是一個 包含參數泛型 Base 的結構體

public struct Reactive<Base> {
    public let base: Base
    # 將 Reactive 的初始化調用者 設置爲 base
    public init(_ base: Base) {
        self.base = base
    }
}
複製代碼

如上文中 點擊按鈕的 tap,即 button.rx.tap, 類型就是 UIButton 類型,將 UIButton 的實例 設置爲 base

那麼想 實現 萬物皆rx,只須要簡單的一步

extension NSObject: ReactiveCompatible { }
複製代碼

這樣就可讓全部繼承於 NSObjce 的對象,都遵循 ReactiveCompatible 協議,即 萬物皆rx


Observable

Observable 意味着,可被觀察的,也就是可觀察序列,什麼是序列呢?

我理解的就是 具有 發出事件能力的 的一種信號


好比:

肚子餓了 -> 吃飯

肚子餓了 能夠做爲一個 可觀察序列,當咱們大腦感知到 肚子餓了,就能夠執行 去吃飯的操做


TextField 輸入 -> 顯示

TextField 輸入操做能夠做爲一個序列,能夠監聽到 輸入的內容


接下來

就開始調試 mojito 了

看一個訂閱過程:

# 建立
let observable = Observable<String>.create { (observe) -> Disposable in
    # 發送
    observe.onNext("mojito")
    return Disposables.create()
}
# 訂閱
observable.subscribe(onNext: { text in
    print(text)
}).disposed(by: rx.disposeBag)

// print "mojito"
複製代碼


調試開始

Observable 可觀察序列

  • step1
# Observable 繼承於 ObservableType
public class Observable<Element> : ObservableType {
    # 資源的引用計數 +1
    init() {
        _ = Resources.incrementTotal()
    }
     # 提供被訂閱的能力,由子類實現
    public func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
        rxAbstractMethod()
    }
     # 將 Observable 類轉爲 Observable 實例
    public func asObservable() -> Observable<Element> {
        return self
    }
     # 資源的引用計數 -1
    deinit {
        _ = Resources.decrementTotal()
    }
}
複製代碼

但是這裏並無看到序列的建立,可是能夠看到一個 繼承關係: Observable<Element> : ObservableType

進入 ObservableType

  • step2
# 協議 ObservableType,繼承於 ObservableConvertibleType
public protocol ObservableType: ObservableConvertibleType {
    func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element
}

# ObservableType 擴展
extension ObservableType {
    # 提供了一個方法,將遵照 ObservableType 協議的對象 轉爲 Observable 實體
    public func asObservable() -> Observable<Element> {
        return Observable.create { o in
            return self.subscribe(o)
        }
    }
}
複製代碼

這裏仍是 沒有看到 訂閱的方法

還發現了 本身的爸爸是個協議, 還有爺爺 ObservableConvertibleType


持着懷疑的態度,你又點進了 ObservableConvertibleType

  • step3
# 也是個協議
public protocol ObservableConvertibleType {

    associatedtype Element
    typealias E = Element
    
    # 定義了一個方法,返回類型 Observable 可觀察序列
    func asObservable() -> Observable<Element>
}

複製代碼


可惡

既然這條路走不通,只能先不走了

哪裏跌倒

我就躺在哪裏

爲了達到萬物皆序列,咱們就要想辦法把全部事件轉化爲序列,asObservable() 即爲 RxSwift 的精髓


Observable.create()

點擊 creat ,豁然開朗,原來建立是經過 ObservableType 擴展,這也同時證實了 OOP 的好處,可擴展性強

ObservableType 像是一家名叫 ObservableType 的連鎖公司

它能夠在任何地方開個分店

實現本身公司的業務

  • step4
# ObservableType 的擴展
extension ObservableType {
    public static func create(_ subscribe: @escaping (AnyObserver<Element>) -> Disposable) -> Observable<Element> {
        # 返回一個 匿名觀察序列,將 subscribe 逃逸閉包傳入
        return AnonymousObservable(subscribe)
    }
}
複製代碼

點擊 AnonymousObservable 進入

  • step5
# 私有方法,外界沒法共享
# AnonymousObservable 繼承於 Producer
final private class AnonymousObservable<Element>: Producer<Element> {
    typealias SubscribeHandler = (AnyObserver<Element>) -> Disposable
    # 定義 閉包屬性
    let _subscribeHandler: SubscribeHandler
    # 將外界傳入的 閉包 保存
    init(_ subscribeHandler: @escaping SubscribeHandler) {
        self._subscribeHandler = subscribeHandler
    }
    # 重寫 父類 Producer 提供的 run 方法
    override func run<Observer: ObserverType>(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
        # 初始化匿名管道,傳入一個訂閱者
        let sink = AnonymousObservableSink(observer: observer, cancel: cancel)
        let subscription = sink.run(self)
        return (sink: sink, subscription: subscription)
    }
}
複製代碼

這裏又來了個 Producer,點擊 Producer

  • step6
# Producer 一樣繼承於 Observable
class Producer<Element> : Observable<Element> {
    override init() {
        super.init()
    }

# 這裏涉及到了線程,若是 CurrentThreadScheduler 指定了某個線程,那麼就會在指定線程中 執行 run
# 不然 就會在當前線程中 執行 run
# SinkDisposer實例 disposer,用來管理資源釋放
override func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
         if !CurrentThreadScheduler.isScheduleRequired {
            // The returned disposable needs to release all references once it was disposed.
            let disposer = SinkDisposer()
            let sinkAndSubscription = self.run(observer, cancel: disposer)
            disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)
            return disposer
        }
        else {
            return CurrentThreadScheduler.instance.schedule(()) { _ in
                let disposer = SinkDisposer()
                let sinkAndSubscription = self.run(observer, cancel: disposer)
                disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)
                return disposer
            }
        }
  }
# 抽象方法,子類去實現,也就是匿名序列 AnonymousObservable
func run<Observer: ObserverType>(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
    rxAbstractMethod()
    }
}
複製代碼

相信到此,你我都已經微醺了

你問我什麼是 序列

我 指 着 大 海 的 方 向


目前也只能先畫個圖,繼續觀望


小結

  • 小結

    • 咱們調用父類協議的 creat 方法 ,生成 匿名觀察序列,即Producer 的子類AnonymousObservable
    • AnonymousObservable 保存外界傳入的 閉包
    • 負責資源管理,引用計數的 是 Observable 抽象類,不實現方法
    • Producer 類 實現 外界 subscribe 方法,並安排線程調度
    • 具體的 run,由 AnonymousObservable 實現,父類 Producer不負責

ok ,繼續往下走

subscribe(onNext:) 訂閱

點擊 subscribe 進入,能夠看到 ObservableType 的擴展,提供了 subscribe.onsubscribe.onNext 2個方法

此處省略了 subscribe.on

  • step7
extension ObservableType {
    ...
    
    public func subscribe(onNext: ((Element) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil)
        -> Disposable {
            ....
            # 建立一個 匿名訂閱者 AnonymousObserver
            # 對外界傳入的執行閉包 進行保存
            let observer = AnonymousObserver<Element> { event in
                switch event {
                case .next(let value):
                    onNext?(value)
                case .error(let error):
                    if let onError = onError {
                        onError(error)
                    } else { Hooks.defaultErrorHandler(callStack, error) }
                    disposable.dispose()
                case .completed:
                    onCompleted?()
                    disposable.dispose()
                }
            }
            return Disposables.create(
                self.asObservable().subscribe(observer),
                disposable
            )
    }
}
複製代碼

這裏將 外界須要執行的 閉包,即本例中的 print(text),生成 AnonymousObserver 實例,傳入

self.asObservable().subscribe(observer)

也就是說,這個 AnonymousObserver實例,會經過 Producer 調用 subscribe

而後由 子類 AnonymousObservable,序列實例去調用 run方法


來到文中,step 5 的 run 方法,以下

# 將外界 須要執行的閉包 ,以及 資源銷燬實例 生成的 元祖 傳入 AnonymousObservableSink
# 生成 sink 管道實例,並執行 run 
# 將run 以後生成的實例,賦值給 subscription,並返回 subscription 和 sink

override func run<Observer: ObserverType>(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
    let sink = AnonymousObservableSink(observer: observer, cancel: cancel)
    let subscription = sink.run(self)
    return (sink: sink, subscription: subscription)
}
複製代碼

進入 AnonymousObservableSink

  • step8
final private class AnonymousObservableSink<Observer: ObserverType>: Sink<Observer>, ObserverType {
    typealias Element = Observer.Element 
    typealias Parent = AnonymousObservable<Element>
    
    # 調用父類 Sink 的初始化方法,傳入 observer 和 cancel,即 管道 AnonymousObservableSink 持有 這2個屬性
    override init(observer: Observer, cancel: Cancelable) {
        super.init(observer: observer, cancel: cancel)
    }

    func on(_ event: Event<Element>) {
        switch event {
        case .next:
            if load(self._isStopped) == 1 {
                return
            }
            self.forwardOn(event)
        case .error, .completed:
            if fetchOr(self._isStopped, 1) == 0 {
                self.forwardOn(event)
                self.dispose()
            }
        }
    }
    ### 熟悉的東西有沒有
    # 這裏看到了 _subscribeHandler,也就是 發出的信號,保存的閉包
    
    func run(_ parent: Parent) -> Disposable {
        return parent._subscribeHandler(AnyObserver(self))
    }
}

複製代碼

到這裏,咱們就會發現 sink 管道 它很重要

它持有了

要銷燬的實例,發出序列的閉包,執行序列的閉包

這裏的  AnyObserver(self) 是爲了 兼容傳入 閉包的類型, 本文對應的 是 String
複製代碼

也就是說,一旦外界開始訂閱序列

那麼 火車序列 就開始發動了,可是 怎麼響應? 下一步往哪開?

這就要看 AnyObserver(self),作了什麼,進入 AnyObserver, 查看init


public init<Observer: ObserverType>(_ observer: Observer) where Observer.Element == Element {
    self.observer = observer.on
}
複製代碼

你會發現這裏的 self.observer 保存了 本身的 on 方法

也就是保存的了一個 function

即 會調用 step8 中 的 on, 而後 去調用 父類Sink 的 forwardOn


  • step9
# 父類 Sink
class Sink<Observer: ObserverType> : Disposable {
    final func forwardOn(_ event: Event<Observer.Element>) {
        #if DEBUG
            self._synchronizationTracker.register(synchronizationErrorMessage: .default)
            defer { self._synchronizationTracker.unregister() }
        #endif
        if isFlagSet(self._disposed, 1) {
            return
        }
        # 訂閱者
        self._observer.on(event)
    }
}
複製代碼

在父類 forwardOn中, 由訂閱者執行 on 事件

但是 訂閱者 AnonymousObserver 類有沒有 on 方法,只有 onCore

因此去 AnonymousObserver 的 父類中 ObserverBase 尋找

class ObserverBase<Element> : Disposable, ObserverType {
    private let _isStopped = AtomicInt(0)

    func on(_ event: Event<Element>) {
        switch event {
        case .next:
            if load(self._isStopped) == 0 {
                self.onCore(event)
            }
        case .error, .completed:
            if fetchOr(self._isStopped, 1) == 0 {
                self.onCore(event)
            }
        }
    }
    # 子類實現
    func onCore(_ event: Event<Element>) {
        rxAbstractMethod()
    }
}
複製代碼

最後 AnonymousObserver 調用本身的 onCore 執行 eventHandler 閉包

到此

整個執行的過程算是走完了

關於資源回收的內容,後續文章會寫到


到此

mojito 初體驗 結束

小結

  • 小結
    • 經過 AnonymousObservable 保存 可觀察序列
    • 經過 AnonymousObserve 保存 執行閉包
    • 外界開始訂閱,由 Producer 調度線程,執行 subscribe
    • 生成 SinkDisposer 以及 observer 實例 元祖
    • 將 元祖 注入 Sink 管道
    • Sink 處理事件,發出信號,響應序列
    • 資源回收

簡單的流程圖以下


而個人寫法,輕鬆像魔法

有了RxSwift ,平常開發就變得酣暢淋漓了,好比

  • 監聽 tableView 的滾動:
tableView.rx.contentOffset.subscribe(onNext: { contentOffset in
    /// 修改透明度
 })
.disposed(by: rx.disposeBag)
複製代碼

  • 監聽textField 輸入
textField.rx.text.skip(1).subscribe(onNext: { (text) in
    print("輸入的是 : \(text!)")
 })
 .disposed(by: rx.disposeBag)
複製代碼

  • 按鈕點擊
self.messageBtn.rx.tap.subscribe(onNext: { in
    Navigator.push("")
 })
 .disposed(by: rx.disposeBag)
複製代碼

  • tableView 綁定數據源 代理
# 這裏須要導入 RxDataSources
  dataSource = RxTableViewSectionedReloadDataSource(configureCell: { (_, tab, indexPath, item) -> UITableViewCell in
    let cell = tab.dequeue(Reusable.settingCell, for: indexPath)
    cell.bind(to: item)
    return cell
  })
  
  # 或者
  let items = Observable.just([
    "Just",
    "Relay",
    "From",
    "Driver",
    "merge"
  ])
  
 items.bind(to: tableView.rx.items) { (tableView,_,element) in
    let cell = self.tableView.dequeue(TestV.normalCell)
    cell?.textLabel?.text = element
    return cell!
  }
  .disposed(by: rx.disposeBag)
複製代碼

  • tableView 點擊代理
tableView.rx.itemSelected.subscribe(onNext: { indexPath in
   /// doSomething
 })
 .disposed(by: rx.disposeBag)
複製代碼

  • 配合 HandyJSON 轉model
extension Response {
    func mapHandyJsonModel<T: HandyJSON>(_ type: T.Type) -> T {
        let jsonString = String.init(data: data, encoding: .utf8)
        if let modelT = JSONDeserializer<T>.deserializeFrom(json: jsonString) {
            return modelT
        }
        return JSONDeserializer<T>.deserializeFrom(json: "{\"msg\":\"解析有誤\"}")!
    }
}

extension ObservableType where Element == Response {
    /// 註釋
    public func mapHandyJsonModel<T: HandyJSON>(_ type: T.Type) -> Observable<T> {
        return flatMap { response -> Observable<T> in
            return Observable.just(response.mapHandyJsonModel(T.self))
        }
    }
}

# 配合 Moya 
static func getTopList() -> Observable<HomeResponseModel> {
    return HomeApiProvider.rx.request(.Top).asObservable().mapHandyJsonModel(HomeResponseModel.self)
}
複製代碼

  • 多個請求合併
Observable.zip(HomeApi.getTopList(), HomeApi.getRecommondList()).subscribe(onNext: { topResponse, recommodResponse in
    /// 數據處理
  }).disposed(by: self.rx.disposeBag)
複製代碼

等等....

先介紹一點簡單的用法

後續會慢慢更新


這世界因我讓你再也不受折磨

RxSwift 熟悉了以後,會讓咱們的代碼變得 簡潔且優雅

它面向協議編程,咱們面向業務編程

RxSwift 須要慢慢品味

聽一遍 mojito 確定是不夠的

不說了

聽歌去了~


對了

RxSwift 中文網

沒喝過 mojito 的 就從這裏開始吧~

相關文章
相關標籤/搜索