ReSwift

ReSwift的使用

ReSwift是单向数据流

Redux(数据流动图)

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

Store

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

let mainStore = Store(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)