美文网首页swift
RxSwift/Moya/Codable在MVVM中的使用

RxSwift/Moya/Codable在MVVM中的使用

作者: 我要在河边钓一整天的鱼 | 来源:发表于2017-11-03 17:53 被阅读610次

    参考资料

    1.MVVM-维基百科
    2.MVVM with RxSwift
    3.RxSwift
    4.RxSwift 学习指导
    5.Moya
    5.Codable

    实现

    这里只解释我对MVVM的理解,不再对RxSwift、Moya、Codable、MVVM做过多的叙述,相信Google会让你知道的更多。

    一、目录结构

    目录结构.png

    二、网络请求

    1、相同格式数据的处理

    对于Json的数据返回会有一个统一的返回格式

    我们公司的Json格式,这三个字段是铁打不会变的,改变的只是data的数据。

    {
        code:Int,
        data:[],
        message:String
    }
    

    练习使用的是豆瓣的一个接口 ("https://api.douban.com/v2/movie/top250")

    class ReponseData<T: Codable>: Codable {
        var count: Int?
        var start: Int?
        var total: Int?
        var subjects: T?
    }
    
    

    3.对Moya的封装

    Moya官方有一个和RxSwfit对接的扩展也可以直接使用哪个;

    Json转Model使用的Codable。

    (1)Moya URL的配置文件

    Moya对URL的配置

    import Foundation
    import Moya
    
    enum APIConfig {
        case top
    }
    
    extension APIConfig: TargetType {
        var sampleData: Data {
            return "{}".data(using: .utf8)!
        }
        
        var task: Task {
            return .requestPlain
        }
        
        var headers: [String : String]? {
            return nil
        }
        
        var baseURL: URL {
            return URL.init(string: "https://api.douban.com/v2/movie/")!
        }
        
        var path: String {
            switch self {
            case .top:
                return "top250"
            }
        }
        
        var method: Moya.Method {
            switch self {
            case .top:
                return .get
            }
        }
    }
    

    (2)Request封装

    func request <Element: Codable> (config: APIConfig) -> Observable<ResponseResult<Element>> {
            return Observable.create({[weak self] (observable) -> Disposable in
                let provider = MoyaProvider<APIConfig>()
                let callBack = provider.request(config, completion: { (responseResult) in
                    switch responseResult {
                    case let .success(response):
                        do {
                            let decoder = JSONDecoder()
                            let data = try decoder.decode(ReponseData<Element>.self, from: response.data)
                            let subjects = data.subjects
                            
                            let result = (subjects == nil) ? ResponseResult.empty : ResponseResult.succeed(data: subjects!)
                            observable.onNext(result)
                        }catch let error {
                            self?.requestError(message: error.localizedDescription)
                            observable.onNext(ResponseResult.failed(message: error.localizedDescription))
                        }
                    case let .failure(error):
                        self?.requestError(message: error.localizedDescription)
                        observable.onNext(ResponseResult.failed(message: error.localizedDescription))
                    }
                })
                return Disposables.create {
                    callBack.cancel()
                }
            })
        }
    

    错误这样处理是为了一些弹框的统一处理,且使用对象也获得错误信息可以做一些特殊处理。

    三、Model

    它只对各种数据和业务进行处理然后更新ViewModel;

    不要含有任何UIKit类.

    class Model: NSObject {
    
        public func getData() -> Observable<ResponseResult<[Subjects]>> {
            return HttpClient().request(config: APIConfig.top)
        }
    }
    

    四、View

    包含ViewController、View、storyboard文件,view是对业务是无感的,只做界面展示和用户交互。

    class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
        @IBOutlet private weak var tableView: UITableView!
        private var viewModel: ViewModel = ViewModel()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            tableView.tableFooterView = UIView()
            viewModel.getData {[weak self] (status) in
                self?.tableView.reloadData()
            }
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
        
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return viewModel.getItemCount()
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell: TopTableViewCell = tableView.dequeueReusableCell(withIdentifier: "TopTableViewCell", for: indexPath) as! TopTableViewCell
            cell.title.text = viewModel.getBindData(index: indexPath.row).title.value
            return cell
        }
    }
    

    五、ViewModel

    协调View和Model、数据的存储。

    class ViewModel: NSObject {
        private var model = Model()
        private var list = [Subjects]()
        private var errorMessage: String = ""
        
        func getData(callBack: @escaping (_ result: RequestStatus) -> Void) {
            model.getData().subscribe(onNext: {[weak self] (result) in
                switch result {
                case .empty:
                    callBack(.empty)
                case .succeed(let data):
                    self?.list = data
                    callBack(.succees)
                case .failed(let errorMessage):
                    self?.errorMessage = errorMessage
                    callBack(.failed)
                }
            }).disposed(by: rx_disposeBag)
        }
        
        func getItemCount() -> Int {
            return list.count
        }
        
        func getBindData(index: Int) -> BindingData {
            return BindingData.init(list[index].title)
        }
        // 获取网络错误信息
        func getErrorMessage() -> String {
            return errorMessage
        }
    }
    

    以上是我对MVVM的理解,每个人对MVVM都有自己不同的理解,有什么疑问或者问题或者好的建议欢迎指正。
    项目地址


    谢谢观看

    相关文章

      网友评论

        本文标题:RxSwift/Moya/Codable在MVVM中的使用

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