The resources

MVVM- Wikipedia 2.MVVM with RxSwift 3.RxSwift 4.RxSwift study guide 5.Moya 5.Codable

implementation

This is just to explain what I know about MVVM. I won’t cover RxSwift, Moya, Codable, and MVVM for more information on Google.

1. Directory structure

Second, network request

1. Processing of data in the same format

There is a uniform return format for Json data returns

In the Json format of our company, these three fields will not be changed. What is changed is only the data of data.

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

Practice using douban is an interface (” https://api.douban.com/v2/movie/top250 “)

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

Copy the code

3. Encapsulation of Moya

Moya has an extension that connects to RxSwfit, which can also be used directly; Json to Model use Codable.

(1) Configuration file of Moya URL

Moya URL configuration

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
        }
    }
}
Copy the code

(2) Request encapsulation

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 leterror { 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()
            }
        })
    }
Copy the code

Error handling is for the unified handling of some popboxes, and using objects to get error messages can do some special processing.

Third, the Model

It just processes the data and the business and updates the ViewModel; Don’t include any UIKit classes.

class Model: NSObject {

    public func getData() -> Observable<ResponseResult<[Subjects]>> {
        return HttpClient().request(config: APIConfig.top)
    }
}
Copy the code

Fourth, the View

It contains ViewController, View, storyboard files. The View is insensitive to the business and only does interface display and user interaction.

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) inself? .tableView.reloadData() } } override funcdidReceiveMemoryWarning() {
        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
    }
}
Copy the code

Fifth, the ViewModel

Coordinate View, Model and data storage.

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(letdata): self? .list = data callBack(.succees)case .failed(leterrorMessage): self? .errorMessage = errorMessage callBack(.failed) } }).disposed(by: rx_disposeBag) } func getItemCount() -> Int {return list.count
    }
    
    func getBindData(index: Int) -> BindingData {
        returnFunc getErrorMessage() -> String {bindingData.init (list[index].title)}return errorMessage
    }
}
Copy the code

The above is my understanding of MVVM, everyone has their own different understanding of MVVM, any questions or questions or good suggestions are welcome to point out. The project address


Thank you for watching