iOS-老生常谈MVC、MVP、MVVM

2020-04-17  本文已影响0人  Simple_Code

MVC(apple版)

image.png

视图(View):用户界面.
控制器(controller):业务逻辑
模型(Model): 数据

C层主要代码:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cellID: String = "CellID"
        var cell: UITableViewCell?
        cell = tableView.dequeueReusableCell(withIdentifier: cellID)
        if cell == nil {
            cell = UITableViewCell(style: .subtitle, reuseIdentifier: cellID)
        }
        
        var model = MVCModel()
        model = dataArray[indexPath.row]
        
        cell?.textLabel?.text = model.title
        cell?.detailTextLabel?.text = model.detail! + String(indexPath.row)
        return cell!
    }

V使用的事系统自带的UITableViewCell
M层代码:

struct MVCModel: Convertible {
    var title: String?
    var detail: String?

    static func arrayModel() -> [MVCModel] {
        let array: [[String: Any]] = [
            ["title":"MVC",
            "detail":"detail"],
            ["title":"MVC",
            "detail":"detail"],
            ["title":"MVC",
            "detail":"detail"],
            ["title":"MVC",
            "detail":"detail"],
            ["title":"MVC",
            "detail":"detail"],
            ["title":"MVC",
            "detail":"detail"],
            ["title":"MVC",
            "detail":"detail"],
        ]
        return array.kj.modelArray(MVCModel.self)
    }
}

实现效果


image.png

结论
如上代码可以看出VM是完全独立的、所有的逻辑处理都在C

优点:View、Model可以重复利用,可以独立使用
缺点:Controller的代码过于臃肿

MVC(变种)

image.png

C层主要代码

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cellID: String = "CellID"
        var cell: MVCCell?
        cell = tableView.dequeueReusableCell(withIdentifier: cellID) as? MVCCell
        if cell == nil {
            cell = MVCCell(style: .subtitle, reuseIdentifier: cellID)
        }
        
        var model = MVCModel()
        model = dataArray[indexPath.row]
        
        cell?.model = model
        
        return cell!
    }

V层主要代码:

    var model: MVCModel? {
        didSet {
            guard let tempModel = model else {
                return
            }

            titleLabel.text = tempModel.title! + "变种"
            detailLabel.text = tempModel.detail! + "变种"
        }
    }

M层代码:

struct MVCModel: Convertible {
    var title: String?
    var detail: String?

    static func arrayModel() -> [MVCModel] {
        let array: [[String: Any]] = [
            ["title":"MVC",
            "detail":"detail"],
            ["title":"MVC",
            "detail":"detail"],
            ["title":"MVC",
            "detail":"detail"],
            ["title":"MVC",
            "detail":"detail"],
            ["title":"MVC",
            "detail":"detail"],
            ["title":"MVC",
            "detail":"detail"],
            ["title":"MVC",
            "detail":"detail"],
        ]
        return array.kj.modelArray(MVCModel.self)
    }
}

实现效果:


image.png

结论:
如上代码可以看出V是拥有M的、数据复制逻辑处理都在V

优点:对Controller进行瘦身,将View内部的细节封装起来了,外界不知道View内部的具体实现
缺点:View依赖于Model

MVP

image.png

C层代码

class MVPViewController: UIViewController {

    var presenter: MVPPresenter?
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        
        presenter = MVPPresenter(vc: self)
    }

}

P层代码

class MVPPresenter: NSObject {
    var viewController: UIViewController?
    
    init(vc : UIViewController) {
        super.init()
        viewController = vc
        setUp()
    }
    
    func setUp() {
        
        // 创建View
        let mView = MVPView()
        viewController?.view.addSubview(mView)
        mView.snp.makeConstraints { (make) in
            make.left.top.right.equalToSuperview()
            make.height.equalTo(600)
        }
        
        // 赋值数据
        mView.titleLabel.text = MVPModel.model().title
        mView.imageView.image = UIImage(named: MVPModel.model().image!)
    }
}

V层代码

class MVPView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        addSubView()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
  
    lazy var imageView: UIImageView = {
        let imageView = UIImageView()
        return imageView
    }()
    lazy var titleLabel: UILabel = {
        let label = UILabel()
        label.text = "MVC变种"
        label.textColor = UIColor.HEX(hex: 0x000000)
        label.font = UIFont.boldSystemFont(ofSize: 24)
        label.numberOfLines = 1
        return label
    }()
}

extension MVPView {
    func addSubView()  {
        addSubview(imageView)
        addSubview(titleLabel)
        
        imageView.snp.makeConstraints { (make) in
            make.centerX.centerY.equalToSuperview()
            make.width.equalTo(200)
            make.height.equalTo(100)
        }
        titleLabel.snp.makeConstraints { (make) in
            make.centerX.equalToSuperview()
            make.centerY.equalTo(imageView.snp.bottom).offset(20)
        }
    }
}

M层代码

struct MVPModel: Convertible {
    var title: String?
    var image: String?

    static func model() -> MVPModel {
        let dict: [String: Any] = ["title":"龙妈",
                                   "image":"long.jpg"]
            
        return dict.kj.model(MVPModel.self)
    }
}

MVVM

image.png

C层代码

import UIKit

class MVVMViewController: UIViewController {
    var viewModel: MVVMViewModel?
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        viewModel = MVVMViewModel(vc: self)
        
    }
    
}

MV层代码

import UIKit

class MVVMViewModel: NSObject {
    var viewController: UIViewController?
    
     @objc dynamic var title: String?
     @objc dynamic var image: String?
    
    init(vc : UIViewController) {
        super.init()
        viewController = vc
        setUp()
    }
    
    func setUp() {
       
        // 创建View
        let mView = MVVMView()
        viewController?.view.addSubview(mView)
        mView.snp.makeConstraints { (make) in
            make.left.top.right.equalToSuperview()
            make.height.equalTo(600)
        }
       
        
        // 赋值数据
        mView.viewModel = self
        title = MVVMModel.model().title
        image = MVVMModel.model().image

    }
    
}

V层代码

import UIKit

class MVVMView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        addSubView()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
  var viewModel: MVVMViewModel? {
      didSet {
        
        self.kvoController.observe(viewModel, keyPath: "title", options: .new) { (observe, object, change) in
            let newValue = change["new"] as? String
            self.titleLabel.text = newValue
        }
        self.kvoController.observe(viewModel, keyPath: "image", options: .new) { (observe, object, change) in
            
            let newValue = change["new"] as? String
            self.imageView.image = UIImage(named: newValue!)
        }
       
      }
  }
    lazy var imageView: UIImageView = {
        let imageView = UIImageView()
        return imageView
    }()
    lazy var titleLabel: UILabel = {
        let label = UILabel()
        label.textColor = UIColor.HEX(hex: 0x000000)
        label.font = UIFont.boldSystemFont(ofSize: 24)
        label.numberOfLines = 1
        return label
    }()
}

extension MVVMView {
    func addSubView()  {
        addSubview(imageView)
        addSubview(titleLabel)
        
        imageView.snp.makeConstraints { (make) in
            make.centerX.centerY.equalToSuperview()
            make.width.equalTo(200)
            make.height.equalTo(100)
        }
        titleLabel.snp.makeConstraints { (make) in
            make.centerX.equalToSuperview()
            make.centerY.equalTo(imageView.snp.bottom).offset(20)
        }
    }
    
 }


M层代码

struct MVVMModel: Convertible {
    var title: String?
    var image: String?

    static func model() -> MVVMModel {
        let dict: [String: Any] = ["title":"龙妈",
                                   "image":"long.jpg"]
            
        return dict.kj.model(MVVMModel.self)
    }
}

有点:MVVM解决了Controller的代码过于臃肿的问题、并且V和M完全解耦。

上一篇下一篇

猜你喜欢

热点阅读