引入 Store


class Store {

    // 觀察者,用于響應(yīng)狀態(tài)更新,第一個 State? 為舊狀態(tài),第二個 State 為當前狀態(tài)
    typealias Observer = (State?, State) -> Void

    private(set) var state: State  // 當前狀態(tài)
    private var _observers: [UUID: Observer]  // 所有的觀察者

    // 初始化
    init(initailState: State) {
        self.state = initailState
        self._observers = [:]
    }

    // 發(fā)出事件
    func dispatch(event: State.Event) {
        let oldState = self.state
        self.state = State.reduce(self.state, event: event)
        _publish(oldState: oldState, newState: self.state)
    }

    // 訂閱狀態(tài)更新
    func subscribe(observer: @escaping Observer) -> UUID {
        let subscriptionID = UUID() //  UUID 是唯一標識符,該 id 可用于取消訂閱
        _observers[subscriptionID] = observer
        observer(nil, self.state) // 訂閱時,將當前狀態(tài)回放給該觀察者
        return subscriptionID
    }

    // 取消訂閱
    func unsubscribe(_ subscriptionID: UUID) {
        _observers.removeValue(forKey: subscriptionID)
    }

    // 私有方法,通知所有的觀察者,狀態(tài)已經(jīng)更新了
    private func _publish(oldState: State?, newState: State) {
        _observers.values.forEach { observer in
            observer(oldState, newState)
        }
    }
}

如何使用 Store:


func useStore() {
    
     //首先下創(chuàng)建 Store
    let initailState = State(username: "",password: "",loading: false,data: nil,error: nil)
    
    let store = Store(initailState: initailState)

    // 然后,訂閱程序狀態(tài),并且將這些狀態(tài)錄制下來
    // 以下變量 newStates 和 oldStates 用于錄制狀態(tài)歷史
    var newStates: [State] = []
    var oldStates: [State?] = []
    
    let subscriptionID = store.subscribe { (oldState, newState) in
        newStates.append(newState)
        oldStates.append(oldState)
    }
    
    // 然后,模擬輸入用戶名事件和輸入密碼事件
    // 模擬真實事件
    store.dispatch(event: .onUpateUsername("beeth0ven"))
    store.dispatch(event: .onUpatePassword("123456"))
    
    // 取消訂閱
    store.unsubscribe(subscriptionID)
    
    // 最后,比對錄制的狀態(tài)是否符合預(yù)期
    // 描敘預(yù)期
    let expectNewStates = [
        State(username: "",password: "",loading: false,data: nil,error: nil),
        State(username: "beeth0ven",password: "",loading: false,data: nil,error: nil),
        State(username: "beeth0ven",password: "123456",loading: false,data: nil,error: nil)
    ]
    
    let expectOldStates = [
        nil,
        State(username: "",password: "",loading: false,data: nil,error: nil),
        State(username: "beeth0ven",password: "",loading: false,data: nil,error: nil)
    ]
    
    // 比對結(jié)果
    newStates == expectNewStates // 結(jié)果:true ??
    oldStates == expectOldStates // 結(jié)果:true ??
}

這就是如何在測試環(huán)境里面使用 Store,那么在 App 里面如何使用 Store 呢。 一個 相對簡單(并未優(yōu)化) 的方法,就是將 Store 注入到對應(yīng)的組件里面,這里以 ViewController 為例:

  • ViewController 可以使用 store.subscribe 方法訂閱程序的狀態(tài)。當狀態(tài)更新時,比對新舊狀態(tài),然后刷新過時了的 UI。
  • 當用戶觸發(fā)某個事件時,調(diào)用 store.dispatch 方法將事件發(fā)出去,如:當用戶點擊登錄按鈕時,就調(diào)用 store.dispatch(event: .onTriggerLogin)。
  • ViewControllerdeinit 方法里面注銷訂閱 store.unsubscribe(subsriptionID)。

總結(jié)

本節(jié)主要介紹了 純函數(shù) 和 附加作用,期間還演示如何用 純函數(shù) 做狀態(tài)管理的。最后還演化出了一個極簡版的 Redux。希望大家可以從中獲益!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 項目中如果配置比較多的話,store的使用可能不只是在store文件夾里面的文件。比如下面項目結(jié)構(gòu): 例如希望在a...
    liwuwuzhi閱讀 24,064評論 4 7
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,685評論 1 32
  • 1.NSTimer不準時的原因:(1).RunLoop循環(huán)處理時間,每次循環(huán)是固定時間,只有在這段時間才會去查看N...
    稻春閱讀 1,371評論 0 3
  • 1.設(shè)計模式是什么? 你知道哪些設(shè)計模式,并簡要敘述?設(shè)計模式是一種編碼經(jīng)驗,就是用比較成熟的邏輯去處理某一種類型...
    龍飝閱讀 2,305評論 0 12
  • 很長一段時間,內(nèi)心被陰郁的烏云壓著,好像沒有什么可以輕易的取悅自己,精美的食物,流行的服飾,熱播的劇集,都無法給你...
    靜思甜閱讀 569評論 0 1

友情鏈接更多精彩內(nèi)容