ReSwift

作者: 大地零一 | 来源:发表于2019-01-02 16:31 被阅读0次

    ReSwift的使用

    ReSwift是单向数据流

    Redux(数据流动图)

    屏幕快照 2019-01-01 下午11.55.20.png

    Store

    Store是保存App State的对象(还负责dispatch action)

    let mainStore = Store<EatojoyState>(reducer: handleAction, state: nil)
    

    state

    存放在Store里的app的页面的数据和状态

    import Foundation
    import ReSwift
    struct EatojoyState: StateType {
        var lists: [EatojoyModel]?
        var isInitLoading: Bool
        var isRefreshing: Bool
        var isLoadingMore: Bool
        var listsFetched: Bool
        var isDelete: Bool
    }
    

    Action

    1.用户或者程序触发的event
    2.action可以携带params和当前state

    //
    //  EatojoyAction.swift
    //  ReSwiftDemo
    //
    //  Created by jp on 2018/12/27.
    //  Copyright © 2018 jp. All rights reserved.
    //
    
    import Foundation
    import ReSwift
    import RxCocoa
    import RxSwift
    
    enum ListsFetchingActionType {
        case initiate, refresh, loadMore
    }
    
    enum ListsFetchedActionType {
        case refresh, loadMore
    }
    
    struct ListsFetchingAction: Action {
        let type: ListsFetchingActionType
    }
    
    struct ListsFetchedAction: Action {
        let lists: [EatojoyModel]
        let type: ListsFetchedActionType
    }
    
    struct ItemDeleteAction: Action {
        let index: Int
    }
    
    let disposeBag = DisposeBag()
    
    func getLists(isLoadMore: Bool, isInitial: Bool = false) {
        if isInitial {
            mainStore.dispatch(ListsFetchingAction(type: .initiate))
        } else {
            if isLoadMore {
                mainStore.dispatch(ListsFetchingAction(type: .loadMore))
            } else {
                mainStore.dispatch(ListsFetchingAction(type: .refresh))
            }
        }
        
        // 
        let urlString = ""
        let url = URL(string: urlString)
        let request = URLRequest(url: url!)
        URLSession.shared.rx.json(request: request).observeOn(MainScheduler.instance).subscribe(onNext: { json in
            print(json)
            if let json = json as? [String: Any], let sourceData = json["data"] as? [String: Any], let lists = sourceData["list"] as? [[String: Any]] {
                let models = lists.map({ item -> EatojoyModel in
                    var initialModel = EatojoyModel(name: "", vendorName: "")
                    initialModel.name = item["name"] as! String
                    initialModel.vendorName = item["vendor_name"] as! String
                    return initialModel
                })
                mainStore.dispatch(ListsFetchedAction(lists: models, type: isLoadMore ? .loadMore : .refresh))
            }
        }).disposed(by: disposeBag)
    }
    

    Reducer

    1.Reducer是一个纯函数
    2.接受一个action和当前的state返回一个新的state

    //
    //  EatojoyReducer.swift
    //  ReSwiftDemo
    //
    //  Created by jp on 2018/12/27.
    //  Copyright © 2018 jp. All rights reserved.
    //
    
    import Foundation
    import ReSwift
    
    func handleAction(_ action: Action, _ state: EatojoyState?) -> EatojoyState {
        return EatojoyState(lists: listsReducer(state: state?.lists, action: action),
                            isInitLoading: isInitLoadingReducer(state: state?.isInitLoading, action: action),
                            isRefreshing: isRefreshingReducer(state: state?.isRefreshing, action: action),
                            isLoadingMore: isLoadingMoreReducer(state: state?.isLoadingMore, action: action),
                            listsFetched: listsFetchedReducer(state: state?.listsFetched, action: action),
                            isDelete: isDeleteItemReducer(state: state?.isDelete, action: action))
    }
    
    func listsReducer(state: [EatojoyModel]?, action: Action) -> [EatojoyModel]? {
        if let action = action as? ListsFetchedAction {
            if action.type == .refresh {
                return action.lists
            } else {
                var initialLists = state ?? [EatojoyModel]()
                initialLists += action.lists
                return initialLists
            }
        }
        
        if let action = action as? ItemDeleteAction, var state = state {
            state.remove(at: action.index)
            return state
        }
        return state
    }
    
    func isInitLoadingReducer(state: Bool?, action: Action) -> Bool {
        if let action = action as? ListsFetchingAction {
            if action.type == .initiate {
                return true
            }
        }
        return false
    }
    
    func isRefreshingReducer(state: Bool?, action: Action) -> Bool {
        if let action = action as? ListsFetchingAction {
            if action.type == .refresh {
                return true
            }
        }
        return false
    }
    
    func isLoadingMoreReducer(state: Bool?, action: Action) -> Bool {
        if let action = action as? ListsFetchingAction {
            if action.type == .loadMore {
                return true
            }
        }
        return false
    }
    
    func listsFetchedReducer(state: Bool?, action: Action) -> Bool {
        return action is ListsFetchedAction
    }
    
    func isDeleteItemReducer(state: Bool?, action: Action) -> Bool {
        return action is ItemDeleteAction
    }
    

    view层监听数据的变化

    //
    //  ViewController.swift
    //  ReSwiftDemo
    //
    //  Created by jp on 2018/12/27.
    //  Copyright © 2018 jp. All rights reserved.
    //
    
    import UIKit
    import ReSwift
    import MJRefresh
    import RxCocoa
    import RxSwift
    
    class ViewController: UIViewController, StoreSubscriber {
        
        var foodstate: EatojoyState?
        @IBOutlet weak var tableView: UITableView!
        @IBOutlet weak var indicatorView: UIActivityIndicatorView!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            getLists(isLoadMore: false, isInitial: true)
            tableView.rowHeight = 100
            tableView.mj_header = MJRefreshNormalHeader(refreshingBlock: {
                getLists(isLoadMore: false, isInitial: false)
            })
            tableView.mj_footer = MJRefreshBackNormalFooter(refreshingBlock: {
                getLists(isLoadMore: true, isInitial: false)
            })
        }
        
        override func viewWillAppear(_ animated: Bool) {
            mainStore.subscribe(self)
        }
        
        override func viewWillDisappear(_ animated: Bool) {
            mainStore.unsubscribe(self)
        }
        
        func newState(state: EatojoyState) {
            foodstate = state
            
            if state.isInitLoading {
                indicatorView.isHidden = false
                indicatorView.startAnimating()
            } else {
                indicatorView.stopAnimating()
                indicatorView.isHidden = true
            }
            
            if state.listsFetched {
                tableView.mj_header.endRefreshing()
                tableView.mj_footer.endRefreshing()
                tableView.reloadData()
            }
            
            if state.isDelete {
                tableView.reloadData()
            }
        }
    }
    
    extension ViewController: UITableViewDelegate, UITableViewDataSource {
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return foodstate?.lists?.count ?? 0
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            if let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? TableViewCell {
                if let model = foodstate?.lists?[indexPath.row] {
                    cell.updateCell(model: model)
                }
    //            cell.deleteBtn.rx.tap.subscribe(onNext: { _ in
    //                mainStore.dispatch(ItemDeleteAction(index: indexPath.row))
    //            }).disposed(by: disposeBag)
                cell.deleteBtn.rx.tap.asDriver().drive(onNext: { _ in
                    mainStore.dispatch(ItemDeleteAction(index: indexPath.row))
                }).disposed(by: cell.bag)
                return cell
            }
            return UITableViewCell()
        }
    }
    

    总结

    ReSwift有哪些优势

    • 很强的约束力:把一些代码放在不合适的地方往往具有很强的诱惑性,虽然这样写很方便。ReSwift 通过很强的约束力来避免这种情况。
    • 单向数据流:多向数据流的代码在阅读和debug上都可能变成一场灾难。一个改变可能会带来一系列的连锁反应。而单向数据流就能让程序的运行更加具有可预测性,也能够减少阅读这些代码的痛苦。
    • 容易测试:大多数的业务逻辑都在Reducer 中,这些都是纯的功能。
    • 父用性:ReSwift 中的每个组件—Store、Reducer、Action ,都是能在各个平台独立运行的,可以很轻松的在iOS、macOS、或者tvOS 中复用这些模块。

    相关文章

      网友评论

          本文标题:ReSwift

          本文链接:https://www.haomeiwen.com/subject/cqnzlqtx.html