MVVM + RxSwift+Moya+HandyJSON项目实战

最近在学习RxSwift ,将学习的过程记录下来。
1、需要用到的相关库:

pod 'RxSwift'
pod 'RxCocoa'
pod 'RxDataSources'
pod 'Moya/RxSwift'
pod 'Moya'
pod 'HandyJSON'

2、使用的是Moya,实现TargetType 协议就可以了。

import Foundation
import Moya

let personalNetWorkProvider = MoyaProvider()

enum personalApi {
    case personal(parameters:[String:Any],path_url:String)
}

extension personalApi: TargetType {
    var baseURL: URL {
        return URL.init(string: BaseURL)!
    }
    
    var path: String {
        switch self {
        case .personal(_,let path_url):
            return path_url
        }
    }
    
    var method: Moya.Method {
        switch self {
        case .personal(_,_):
            return .post
        }
    }
    
    var sampleData: Data {
        return "".data(using: String.Encoding.utf8)!
    }
    
    var task: Task {
        switch self {
        case let .personal(parameters,_):
            return .requestParameters(parameters: parameters, encoding: JSONEncoding.default)
        }
    }
    
    var headers: [String : String]? {
        return nil
    }
}

3、将网络请求回的数据通过JSON转化成Mode ,需要进行一些准备。

import Foundation
import RxSwift
import Moya
import HandyJSON

extension ObservableType where E == Response {
    public func mapHandyJsonModel(_ type: T.Type) -> Observable {
        return flatMap { response -> Observable in
            return Observable.just(response.mapHandyJsonModel(T.self))
        }
    }
}

extension Response {
    func mapHandyJsonModel(_ type: T.Type) -> T {
        let jsonString = String.init(data: data, encoding: .utf8)
        if let modelT = JSONDeserializer.deserializeFrom(json: jsonString) {
            return modelT
        }
        return JSONDeserializer.deserializeFrom(json: "{\"msg\":\"请求有误\"}")!
    }
}

4、定义一个协议

import Foundation

protocol personalViewModeType {
    //associatedtype: 关联类型为协议中的某个类型提供了一个占位名(或者说别名),其代表的实际类型在协议被采纳时才会被指定
    associatedtype Input
    associatedtype Output
    func transform(input:Input)->Output//通过 transform 方法将input携带的数据进行处理,生成了一个Output
}

5、Model

import Foundation
import HandyJSON
import RxDataSources

struct personalModel: HandyJSON {
    var data:tokenModel?
}
struct tokenModel: HandyJSON {
    var token:String?
}
struct personalSection {
    var items: [Item]
}
extension personalSection: SectionModelType {
    typealias Item = personalModel // 重定义 Item 的类型为personalModel
    //实现协议中的方式
    init(original: personalSection,items: [personalSection.Item]) {
        self = original
        self.items = items
    }
}

6、下面是ViewModel中全部代码


import UIKit
import RxSwift
import RxCocoa
import SwiftyJSON
import HandyJSON
import Reachability
import Moya

enum personalRefreshStatus { // tableView的刷新状态
    case none
    case beingHeaderRefresh
    case endHeaderRefresh
    case beingFooterRefresh
    case endFooterRefresh
    case noMoreData
}

class personalViewModel: NSObject {
    let models = Variable<[personalModel]>([]) // 存放着解析完成的模型数组
    private lazy var disposeBag = DisposeBag()
}
extension personalViewModel: personalViewModeType {
    typealias Input = personInput
    
    typealias Output = personaloutput

    struct personInput {
        
    }
    struct  personaloutput {
        
        let sections:Driver<[personalSection]> // tableView的section数据
        let requestCommond = PublishSubject<[String: Any]>() //传递参数进来进行网络请求
        let refreshStatus = Variable(.none) // 告诉外界的tableView当前的刷新状态
        init(sections:Driver<[personalSection]>) {
            self.sections = sections
        }
    }
    
    func transform(input: personalViewModel.personInput) -> personalViewModel.personaloutput {
        let sections = models.asObservable().map { (models) -> [personalSection] in
            return [personalSection(items:models)] // 当models的值被改变时会调用
        }.asDriver(onErrorJustReturn: [])
        let output = personaloutput(sections: sections)
        output.requestCommond.subscribe(onNext: { [weak self] paratem in
            //进行网络请求
            guard (self?.isWifiNetwork())! else { return } // 判断网络状态
            personalNetWorkProvider.rx.request(.personal(parameters: paratem, path_url: login_URL)).asObservable().mapHandyJsonModel(personalModel.self).subscribe({ [weak self] (event) in
                metting_SVPDismiss() // 取消加载动画
                output.refreshStatus.value = .endHeaderRefresh // 告诉外界刷新结束
                switch event {
                case let .next(classModel):
                    self?.models.value = [classModel]
                    break
                case let .error(error):
                    warningTIps(waringStr: error as! String)
                    break
                default:
                    break
                }
                
            }).disposed(by: (self?.disposeBag)!)
            
        }).disposed(by: disposeBag)
        
        return output
    }
    
}
// MARK: - 网络数据
extension personalViewModel {
    private func isWifiNetwork()-> Bool { // p判断当前连接的网络
        let reachability = Reachability()! // 网络检测
        switch reachability.connection {
        case .wifi:
            metting_SVPShow() // 显示加载动画
            return true
        case .none,.cellular:
            alertDismiss(message: "当前不是Wi-Fi或者无网络连接,请连接Wi-Fi")
            return false
        }
    }
}

7、最后是ViewController中代码

import UIKit
import RxCocoa
import RxSwift
import Then
import RxDataSources
import MJRefresh

class personalViewController: JFBaseViewController {

    private lazy var disposeBag = DisposeBag()
    
    let viewModel = personalViewModel()
    
    private lazy var headView: personalHeaderView = {
        let headView = personalHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenW, height: AdaptH(90)))
        return headView
    }()
    
    let tableView = UITableView().then {
        $0.backgroundColor = kWhite
        $0.register(personalTableViewCell.self, forCellReuseIdentifier: personalTableViewCell.identifier())
        $0.tableFooterView = UIView()
    }
    let dataSource = RxTableViewSectionedReloadDataSource(configureCell: {(ds,tb,index,model) -> personalTableViewCell in
        let cell = tb.dequeueReusableCell(withIdentifier: personalTableViewCell.identifier(), for: index) as? personalTableViewCell
        cell?.textLabel?.text = model.data?.token
        return cell!
    },titleForHeaderInSection: {ds,index in
        return String(index)
    })
    override func viewDidLoad() {
        super.viewDidLoad()
        setUpAll()
        bindView()
    }
}

extension personalViewController {
    fileprivate func setUpAll() {
        view.addSubview(tableView)
        tableView.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }
    }
}

// MARK: - 绑定数据
extension personalViewController {
    fileprivate func bindView() {
        tableView.rx.setDelegate(self).disposed(by: disposeBag)
        let vmInput = personalViewModel.personInput() // 初始化input
        let vmOutput = viewModel.transform(input: vmInput) // 通过transform得到output
        vmOutput.sections.asDriver().drive(tableView.rx.items(dataSource: dataSource)).disposed(by: disposeBag)
        
        vmOutput.refreshStatus.asObservable().subscribe(onNext: { [weak self] status in
            //--
            switch status {
            case .beingHeaderRefresh:
                self?.tableView.mj_header.beginRefreshing()
                break
            case .endHeaderRefresh:
                self?.tableView.mj_header.endRefreshing()
                break
            case .beingFooterRefresh:
                self?.tableView.mj_footer.beginRefreshing()
                break
            case .endFooterRefresh:
                self?.tableView.mj_footer.endRefreshing()
                break
            case .noMoreData:
                self?.tableView.mj_footer.endRefreshingWithNoMoreData()
                break
            default:
                break
            }
        }).disposed(by: disposeBag)
        tableView.tableHeaderView = headView
        var parameter = [String: Any]()
        parameter["userName"] = personal_userName
        parameter["pass"] = personal_pass
        vmOutput.requestCommond.onNext(parameter)
        tableView.mj_header = MJRefreshNormalHeader(refreshingBlock: {
            vmOutput.requestCommond.onNext(parameter)
        })
        tableView.rx.itemSelected.subscribe(onNext:{ [weak self] indexPath in
            self?.tableView.deselectRow(at: indexPath, animated: true)
            print(indexPath.row)
        }).disposed(by: disposeBag)
    }
}

// MARK: - UITableViewDelegate
extension personalViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return AdaptH(100)
    }
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return AdaptH(50)
    }
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let headerView = UIView()
        headerView.backgroundColor = kRed
        return headerView
    }
}

效果图:


MVVM + RxSwift+Moya+HandyJSON项目实战_第1张图片
image.png

参考地址:
https://www.jianshu.com/p/d8cf13724fe7
https://www.jianshu.com/p/406336b4aadc
https://www.jianshu.com/p/6678f28db333

你可能感兴趣的:(MVVM + RxSwift+Moya+HandyJSON项目实战)