MVVM+RxSwift简单实践

1、简要说明

  • 使用MVVM去解耦model、view,提高复用的可能性,同时极大减轻了controller的负担,通过中间件viewModel处理数据源、绑定UI、处理逻辑事件。这样当各种业务冗杂在一起的时候,各业务之间的代码可以完全分离,使代码清晰。
  • 使用RxSwift,可以替换掉原有的dataSource,delegate等代理方法,做到异步 Event(事件)序列的响应式编程,方便快捷,并且逻辑更加清晰。
  • 代码中使用了优秀的开源库:Kingfisher,SnapKit。

2、运行效果

3、目录结构

4、页面代码

  • controller
//
//  MainViewController.swift
//  ss
//
//  Created by WES319 on 11/7/18.
//  Copyright © 2018年 周元素. All rights reserved.
//

import UIKit
import RxCocoa
import RxSwift
import SnapKit

class MainViewController: UIViewController {

    var tableView = MainTableView()
    var tableViewModel: MainTableViewModel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.title = "游戏"
        
        tableViewModel = MainTableViewModel.init(target: self)
        
        view.addSubview(tableView)
        tableView.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }
    }
}
  • Model
//
//  ProductModel.swift
//  ss
//
//  Created by WES319 on 12/7/18.
//  Copyright © 2018年 周元素. All rights reserved.
//

import UIKit

class ProductModel: NSObject {

    var image: String
    var title: String
    var content: String
    
    required init(image: String, title: String, content: String) {
        self.image = image
        self.title = title
        self.content = content
        super.init()
    }
 
}
  • View
//
//  MainTableView.swift
//  ss
//
//  Created by WES319 on 11/7/18.
//  Copyright © 2018年 周元素. All rights reserved.
//

import UIKit

class MainTableView: UITableView {

    override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)
        
        self.tableFooterView = UIView()
        self.estimatedRowHeight = 100
        self.register(MainTableViewCell.self, forCellReuseIdentifier: MainTableViewCell.cellID)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
//
//  MainTableViewCell.swift
//  ss
//
//  Created by WES319 on 11/7/18.
//  Copyright © 2018年 周元素. All rights reserved.
//

import UIKit
import Kingfisher

class MainTableViewCell: UITableViewCell {

    static let cellID = NSStringFromClass(MainTableViewCell.self)
    
    var mainImageView = UIImageView()
    var titleLabel = UILabel()
    var contentLabel = UILabel()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        self.separatorInset = UIEdgeInsetsMake(0, 15, 0, 0)
        
        contentView.addSubview(mainImageView)
        mainImageView.snp.makeConstraints { (make) in
            make.top.left.bottom.equalToSuperview().inset(15)
            make.height.equalTo(80).priority(999)
            make.width.equalTo(mainImageView.snp.height).multipliedBy(16.0/9.0)
        }
        
        titleLabel.font = UIFont.systemFont(ofSize: 15, weight: UIFont.Weight.black)
        contentView.addSubview(titleLabel)
        titleLabel.snp.makeConstraints { (make) in
            make.left.equalTo(mainImageView.snp.right).offset(10)
            make.top.equalTo(mainImageView)
            make.right.lessThanOrEqualToSuperview().inset(10)
        }
        
        contentLabel.textColor = UIColor.gray
        contentLabel.font = UIFont.systemFont(ofSize: 13, weight: UIFont.Weight.light)
        contentLabel.numberOfLines = 2
        contentView.addSubview(contentLabel)
        contentLabel.snp.makeConstraints { (make) in
            make.left.equalTo(titleLabel)
            make.top.equalTo(titleLabel.snp.bottom).offset(5)
            make.right.lessThanOrEqualToSuperview().inset(15)
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func update(image: String, title: String, content: String) {
        mainImageView.kf.setImage(with: URL.init(string: image))
        titleLabel.text = title
        contentLabel.text = content
    }
}
  • ViewModel
//
//  MainTableViewModel.swift
//  ss
//
//  Created by WES319 on 11/7/18.
//  Copyright © 2018年 周元素. All rights reserved.
//

import UIKit
import RxSwift

class MainTableViewModel: NSObject {
    
    var dataSource = Observable.just([ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一万年前,妖星蔽日,须弥山中的魔界封印失效。魔帝乘机率领魔军涌入人界,在须弥山顶建立天幻城。一时之间生灵涂炭,火光冲天。浓重的妖魔鬼气蔓延至高高在上的仙佛二界。众仙家佛祖意识到如若人间沦陷,仙、佛二界也难免血光之灾,故如来佛祖与太上老君,联合仙佛二界高手与魔军会战于人间。这场战争最终以魔帝的失败告终,魔帝、魔军、天幻城被打回魔界,魔界入口被重新封印。")
        ,ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一万年前,妖星蔽日,须弥山中的魔界封印失效。魔帝乘机率领魔军涌入人界,在须弥山顶建立天幻城。一时之间生灵涂炭,火光冲天。浓重的妖魔鬼气蔓延至高高在上的仙佛二界。众仙家佛祖意识到如若人间沦陷,仙、佛二界也难免血光之灾,故如来佛祖与太上老君,联合仙佛二界高手与魔军会战于人间。这场战争最终以魔帝的失败告终,魔帝、魔军、天幻城被打回魔界,魔界入口被重新封印。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一万年前,妖星蔽日,须弥山中的魔界封印失效。魔帝乘机率领魔军涌入人界,在须弥山顶建立天幻城。一时之间生灵涂炭,火光冲天。浓重的妖魔鬼气蔓延至高高在上的仙佛二界。众仙家佛祖意识到如若人间沦陷,仙、佛二界也难免血光之灾,故如来佛祖与太上老君,联合仙佛二界高手与魔军会战于人间。这场战争最终以魔帝的失败告终,魔帝、魔军、天幻城被打回魔界,魔界入口被重新封印。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一万年前,妖星蔽日,须弥山中的魔界封印失效。魔帝乘机率领魔军涌入人界,在须弥山顶建立天幻城。一时之间生灵涂炭,火光冲天。浓重的妖魔鬼气蔓延至高高在上的仙佛二界。众仙家佛祖意识到如若人间沦陷,仙、佛二界也难免血光之灾,故如来佛祖与太上老君,联合仙佛二界高手与魔军会战于人间。这场战争最终以魔帝的失败告终,魔帝、魔军、天幻城被打回魔界,魔界入口被重新封印。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一万年前,妖星蔽日,须弥山中的魔界封印失效。魔帝乘机率领魔军涌入人界,在须弥山顶建立天幻城。一时之间生灵涂炭,火光冲天。浓重的妖魔鬼气蔓延至高高在上的仙佛二界。众仙家佛祖意识到如若人间沦陷,仙、佛二界也难免血光之灾,故如来佛祖与太上老君,联合仙佛二界高手与魔军会战于人间。这场战争最终以魔帝的失败告终,魔帝、魔军、天幻城被打回魔界,魔界入口被重新封印。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一万年前,妖星蔽日,须弥山中的魔界封印失效。魔帝乘机率领魔军涌入人界,在须弥山顶建立天幻城。一时之间生灵涂炭,火光冲天。浓重的妖魔鬼气蔓延至高高在上的仙佛二界。众仙家佛祖意识到如若人间沦陷,仙、佛二界也难免血光之灾,故如来佛祖与太上老君,联合仙佛二界高手与魔军会战于人间。这场战争最终以魔帝的失败告终,魔帝、魔军、天幻城被打回魔界,魔界入口被重新封印。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一万年前,妖星蔽日,须弥山中的魔界封印失效。魔帝乘机率领魔军涌入人界,在须弥山顶建立天幻城。一时之间生灵涂炭,火光冲天。浓重的妖魔鬼气蔓延至高高在上的仙佛二界。众仙家佛祖意识到如若人间沦陷,仙、佛二界也难免血光之灾,故如来佛祖与太上老君,联合仙佛二界高手与魔军会战于人间。这场战争最终以魔帝的失败告终,魔帝、魔军、天幻城被打回魔界,魔界入口被重新封印。")])
    weak var target: MainViewController!
    let disposeBag = DisposeBag()
    
    required init(target: MainViewController) {
        self.target = target
        super.init()
        
        // 绑定数据
        self.dataSource.bind(to: target.tableView.rx.items(cellIdentifier: MainTableViewCell.cellID)) { (_, model, cell: MainTableViewCell) in
            cell.update(image: model.image, title: model.title, content: model.content)
        }.disposed(by: disposeBag)
        
        // tableView点击事件
        self.target.tableView.rx.modelSelected(ProductModel.self).subscribe(onNext: { (model) in
            print(model.title)
        }).disposed(by: disposeBag)
        self.target.tableView.rx.itemSelected.subscribe(onNext: { (indexPath) in
            print(indexPath.row)
            self.target.tableView.deselectRow(at: indexPath, animated: true)
        }).disposed(by: disposeBag)
    }
}

你可能感兴趣的:(swift)