Bootstrap

iOS——MVC、MVP、MVVM

MVC

MVC模式是将应用程序分成三个部分的一种架构模式,一般分为:Model(模型),View(视图),Controller(控制器)。各部分功能如下:

  • Model:负责数据的管理,包括数据的结构和逻辑处理,以及获取。
  • View:负责展示页面以及用户的交互
  • Controller:是Model和View的中间桥梁,通过用户的输入实时更新Model和View。

三者关系如图:

MVC的优缺点:

优点:能提高开发效率,减少冗余代码

缺点:会出现大量代码堆积在ViewController中

创建示例:

//MVC Model创建
struct MVCModel {
    let title:String
    let date:String
    let count:Int
}

//MVC View的创建,负责页面展示和用户的交互
class MVCView: UIView {

    private let titleLabel = UILabel()
    private let countLabel = UILabel()
    private let coreImage = UIImageView()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        titleLabel.textColor = .black
        countLabel.textColor = .red
        coreImage.contentMode = .scaleAspectFill
        addSubview(titleLabel)
        addSubview(countLabel)
        addSubview(coreImage)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

//MVC Controller创建,桥梁
class MVCViewController: UIViewController {
    
    let Models = Array<MVCModel>()
    let View = MVCView()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .red
        self.view.addSubview(View)
        // Do any additional setup after loading the view.
    }
}

对Model层的误解、误用:

很多人把Model理解成只是单独的数据模型,比如上面示例中只定义了几个字段,但Model层正确定义是业务模型层,就是所有业务数据以及数据逻辑都应该在Model层中。

Model层的正确设计:

M层要完成对业务逻辑实现的封装,一般业务逻辑最多的是涉及到客户端和服务器之间的业务交互。M层里面要完成对使用的网络协议(HTTP, TCP,其他)、和服务器之间交互的数据格式(XML, JSON,其他)、本地缓存和数据库存储(COREDATA, SQLITE,其他)等所有业务细节的封装,而且这些东西都不能暴露给C层。所有供C层调用的都是M层里面一个个业务类所提供的成员方法来实现。也就是说C层是不需要知道也不应该知道和客户端和服务器通信所使用的任何协议,以及数据报文格式,以及存储方面的内容。这样的好处是客户端和服务器之间的通信协议,数据格式,以及本地存储的变更都不会影响任何的应用整体框架,因为提供给C层的接口不变,只需要升级和更新M层的代码就可以了。比如说我们想将网络请求库从ASI换成AFN就只要在M层变化就可以了,整个C层和V层的代码不变。

MVP

MVP(Model-View-Presenter)是基于MVC误用的一个优化版,MVP也是将业务逻辑和业务展示进行分离。MVP并不是去掉了Controller,而是将Controller和View都合并为了View层,。

各层职责:

Model:数据模型层,定义数据字段,接受数据,更改数据并通知Presenter层。

View:视图层,ViewController也属于View层,负责生成View,管理View的生命周期,实现View的相关代理和数据源。

Presenter:业务逻辑层,类似于MVC中的C层,是Model和View的桥梁,负责View的事件处理逻辑,暴露相应接口给View的事件进行调用,收到Model的数据更新后,更新对应的View。

在MVP中,View的代码非常轻量,几乎不包含任何业务逻辑,,这些业务逻辑都交给Presenter层处理,View和Model也没有交互,所有交互都是通过Presenter层。

优点:将业务逻辑进行了分离。

缺点:View的定义是通过协议进行,代码稍显复杂。

MVVM

MVVM(Model-View-ViewController),和MVP类似,也是MVC的演化版本。

MVVM各层职责:

MVVM和MVP几乎一样,ViewModel层的作用其实和MVP的Presenter层一样,其它层也和MVP一致。

MVVM和MVP唯一不同的地方在于ViewModel层和View层之间加入了Binder层,实现双向绑定,作用是保证Model和View可以同步。

示例代码:

//M
struct MVVMModel {
    var name:String
    var age:Int
}
//V
class MVVMViewController: UIViewController, ViewModelDelegate {
    func UpdateData(_ viewModel: MVVMViewModel) {
        nameLabel.text = viewModel.Text
    }
    
    
    private var viewModel:MVVMViewModel!
    private let nameLabel = UILabel()
    private let Button = UIButton()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let model = MVVMModel(name: "Ally", age: 20)
        viewModel = MVVMViewModel(model: model)
        viewModel.delegate = self
        setupUI()
        
    }
    
    func setupUI(){
        self.view.addSubview(nameLabel)
        nameLabel.textColor = .red
        nameLabel.frame = CGRect(x: 100, y: 400, width: 200, height: 30)
        nameLabel.textColor = .black
        nameLabel.adjustsFontSizeToFitWidth
        nameLabel.text = self.viewModel.Text
        self.view.backgroundColor = .white
        self.view.addSubview(Button)
        Button.setTitle("更改", for: .normal)
        Button.setTitleColor(.blue, for: .normal)
        Button.titleLabel?.font = UIFont(name: "Arial", size: 20)
        Button.frame = CGRect(x: 100, y: 250, width: 150, height: 30)
        Button.addTarget(self,action: #selector(Update), for: .touchUpInside)
    }
    
    
    @objc func Update(){
        self.viewModel.updateData("John", 55)
    }
}

//VM
protocol ViewModelDelegate:AnyObject {
    func UpdateData(_ viewModel:MVVMViewModel)
}
struct MVVMViewModel {
    
    private var model:MVVMModel
    weak var delegate:(ViewModelDelegate)?
    
    var Text:String {
        return "\(model.name) is \(model.age) age"
    }
    
    init(model: MVVMModel) {
        self.model = model
        
    }
    
    mutating func updateData(_ name:String,_ age:Int){
        model.name = name
        model.age = age
        delegate?.UpdateData(self)
    }
    
}

在VM层通过代理delegate、block、kvo、notification等方式实现数据绑定。,使得UI更新十分方便。

;