iOS 分析MVC、MVP、MVVM、VIPER

天天说MVC,尤其对于做iOS开发的,更是口头禅,因为Apple已经为我们量身定制了适合iOS开发的MVC架构。那么什么是MVC?

对于iOS的程序猿来说,MVC人人都说自己会用,但是呢实际开发过程中很多人都会有这样的体会,controller里的代码比较多,尤其需求不断的更改和增加,controller里的代码会越来越多,apple退出的MVC真的有这么不靠谱吗?很多人都会纠结的一个问题,网络请求到底是放在那里比较好呢?

最近闲来无事,我也在网上看看博客,了解了下,结合这些年的开发理解,在此呢也说说我的理解。

注:本文内容中的所以图片都是借鉴别人博客里的,不是自己画的。

1、什么是MVC模式呢?

先来看看下面这张图:

当然这只是最理想的模式情况下,为什么这么说呢,实际运用中就会出现问题,不然也就不会出现其他mvp,mvvm等模式了?。待会说why,我们先看看这幅图的每个层是什么意思:

  • Models: 数据层,负责数据的处理和获取的数据接口层。
  • Views: 展示层,即UI层。
  • Controller: 控制器层,它是 Model 和 View 之间的媒人,负责牵线搭桥的?。当用户对 View 有操作时它负责去修改相应 Model;当 Model 的值发生变化时它负责去更新对应 View。

所以呢V和M因该是完全隔离的,由C在中间做桥梁,同时呢,M、V、C三者也是完全分开的(注意,这里是完全分开,不是隔离,分分开在不通类文件里,但是呢C和M以及C和V是有交互的)。既然V和M是完全隔离的,所以就可以保证M和V的可测试性和复用性,但是C不行,因为C是M和V的中介,所以不能复用,或者说很难复用。

2、实际情况下iOS的MVC模式什么样子的呢?

为什么会是这个样子的呢,为什么实际情况下V和C成了紧耦合了?

这是由于每一个界面的创建都需要一个C,而每一个C里面必然会带一个View,这就导致了C和V耦合了,而大多数是V将事件传递给C,由C通过Delegate或者DataSource负责分派任务或事件给V,这很明显和MVC模式不符呀,于是我看看苹果官方是怎么解释的:

https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/Model-View-Controller/Model-View-Controller.html#//apple_ref/doc/uid/TP40010810-CH14-SW14

所以也能看出,viewcontroller的这种结构确实可以提高开发效率,但是一旦界面建复杂,viewcontroller就很容易出现上千行代码,全是逻辑,对于一些人就会分不清了,我这部分代码到底是该写在V里面呢还是应该写在M,纠结了,尤其是还有很多人将网络请求放在了C里面,真是无语了?。

注释:这里的C统一代理iOS里的VC,方便书写。

3、MVC中每层的具体作用:

C层:

  • 生成view,然后组装view

  • 响应View的事件和作为view的代理
  • 调用model的数据获取接口,拿到返回数据,处理加工,渲染到view显示
  • 处理view的生命周期
  • 处理界面之间的跳转

model层:

  • 业务逻辑封装
  • 提供数据接口给controller使用
  • 数据持久化存储和读取
  • 作为数据模型存储数据

view层:

  • 界面元素搭建,动画效果,数据展示,
  • 接受用户操作并反馈视觉效果

4、现在我们来看看大多数人是怎么来创建table的,看看下面这段代码,是不是很熟悉:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 
    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell"];
    cell.model = self.data[indexPath.row];
    return cell;
}

然后在cell的类里重新model的set方法然后给cell负值。

- (void)setModel:(CustomModel *)model {
    _model = model;
    self.titleLabel.text = ...
}

模型类:

#import <Foundation/Foundation.h>

@interface Model : NSObject

@property (copy, nonatomic) NSString *aaa;
@property (copy, nonatomic) NSString *bbbb;
.....
@end

看到这,可能你看到这都还不明白自己的这样写法有什么问题,那我弱弱的问你一句,你的M就只起一个属性作用吗?后去一值添加需求,你的C会越来月庞大。

5、接下来就说说,倒是什么M层?

首先要纠正一下犯上面那种错误的同胞,M层不仅仅是一个数据模型,他还可以干很多事情的!!!

那么到底什么是M层呢,M层是业务模型。也就是说你所有业务数据和业务实现逻辑都应该定义在M层里面,因为你的业务逻辑的实现和定义是和具体的界面无关的,也就是和视图以及控制之间没有任何的关系,它是可以独立存在的,也就是你用单元测试的时候,是可以直接对立面的业务逻辑进行测试的,不需要运行C层的。说白了就是一块独立的代码块,谁都可以调用。

如果还不理解的话,可以找一个系统的类,他的父类是NSObject类,这个类绝对不会只是一个数据模型,肯定还有很多其他功能的方法或类方法。

6、那么定义M层的原则是什么呢?

  • 定义的M层中的代码应该和V层和C层完全无关的,也就是M层的对象是不需要依赖任何C层和V层的对象而独立存在的。整个框架的设计最优结构是V层不依赖C层而独立存在,M层不依赖C层和V层独立存在,C层负责关联二者,V层只负责展示,M层持有数据和业务的具体实现,而C层则处理事件响应以及业务的调用以及通知界面更新。三者之间一定要明确的定义为单向依赖,而不应该出现双向依赖

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

7、现在看看一下ViewController层

首先知道:ViewController是V和C两层的混合体,并不是真正意义上的C层。

上面已经说了VC层的功能和作用了,那么怎么才能给VC减负呢?

我们可以将VC看成是一个view container。

  • 管理View Container的生命周期

  • 负责生成所有的View实例,并放入View Container

  • 监听来自View与业务有关的事件,通过与Model的合作,来完成对应事件的业务。

做到这三点,就可以大大减少VC的代码,而且逻辑更加清楚,因为每个模块的展示和交互是自管理的, 所以VC只需要负责和自身业务强相关的部分即可。

8、MVC优缺点

优点

前面介绍了VC和C的区别,按照上面的方法,应对一般场景应该够了。不管界面多复杂,都可以拆分成更小的MVC然后再组

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值