什么是MVC?
MVC实际上是一种三层架构思想,将应用程序大体上分为三层View、Model和Controller层。MVC模式定义了这些类型的对象在应用程序及其通信线路中扮演的角色。在设计应用程序时,一个主要步骤是为属于这三组中的对象选择或创建自定义类。这三种类型的对象都通过抽象的边界与其他类型的对象分离,并跨越这些边界与其他类型的对象进行通信
- View:是视图层,负责展示Model层的数据,并允许用户编辑Model中的数据。View不应该负责存储它所显示的数据。(当然,这并不意味着View永远不会实际存储它正在显示的数据。出于性能原因,View可以缓存数据或执行类似的技巧)。
- Model:是业务层,负责保存应用程序的数据并定义操作该数据的逻辑。将数据交给View层展示。
-
Controller:充当应用程序的View层和Model层之间的中介。Controller通常负责确保View能够访问它们需要显示的Model对象,并充当View了解模型更改的管道。Controller对象还可以执行应用程序的设置和协调任务,并管理其他对象的生命周期。
更多内容参考iOS中的MVC;
关于iOS中Controller和ViewController关系
在MVC中,Controller的作用在于让View和Model隔离,也就是解耦。Controller因为负责特定的View和Model的通信,所以通常来说是不能复用的,当然在某些时候也是能够复用的,看具体业务。
在iOS中,我们通常使用ViewController相关的自定义对象来作为Controller层的对象。所以,很多人会自然而然的认为ViewController就是Controller,但是这显然是不正确的。从前面对MVC的描述来看,Controller它是一个层,它是MVC中的C层,它并不指定是某个类某个对象,而ViewController通常是iOS里面我们继承自UIViewController自定义的类的对象,显然ViewController是不等于Controller的。ViewController在某种程度上是一个角色合并的对象,同时具有Controller和View的角色,这也是为什么在iOS中很多人经常出现的ViewController过重的问题。
使用MVC会导致ViewController臃肿吗?
为什么会臃肿?
很多人在iOS中使用MVC为什么ViewController会变重?其实就是因为在iOS中ViewController是页面得一个基本单位,大部分正常情况下,一个页面会有一个ViewController,由于ViewController是一个角色合并的对象,iOS中ViewControler不但要管理视图层级和管理对象生命周期,还要负责View和Model之间的通信。而很多人为了方便,甚至把Model相关的业务逻辑都放在ViewController 来实现,导致ViewControler任务过于繁重。综上所述,ViewController变重的我觉得主要有如下两点原因:
- 第一点可能是把View和Model相关的业务都让ViewController来实现了;
- 第二点就是页面很复杂,需要管理的View和Model比较多,导致ViewController代码很多。
对于第一点,这显然是违反MVC框架的初衷的。Controller层应该只是扮演中介者和协调者的角色,而这里面实际上ViewControler不只是扮演Controller的,还同时拥有View和Model的角色,承担了很多不该属于自己的任务。而对于第二点,我觉得这不是MVC本身的问题。实际上如果某个类或者说某个模块本身功能比较复杂,那么代码量相应的比较多是正常的,这个跟使用什么框架没有关系。
如何解决臃肿的问题?
类似ViewController这样的臃肿问题,其实主要是因为在使用过程中没有定位清楚,在一个类上添加各种各样的功能,耦合性很大。这不仅维护起来很麻烦,也很难复用。如果我们将这些功能分别用不同的类或分类来实现,进行解耦,后期的需求变更和维护就会互不影响,还能够降低类的复杂度,提高可读性,总的来讲就是一个类、接口、方法只负责一项职责。这其实也是所谓的模块化,对于面向对象语言,我们本就应该习惯于进行模块化开发,把一个臃肿的类或对象再次细分成不同的模块,细分模块可以是自定义新的类,也可以使用分类(Category)。
何时使用其他类?何时使用分类?
这主要根据业务需求来看,我认为一个比较简单的标准就是,细分出的子模块是否可以被与当前类无关的其他类所复用,如果可以被其他类所复用,那显然自定义新的类比较合适;如果当前的子模块只被当类或其子类使用,显然使用分类更加合适。
使用MVVM就能解决ViewController臃肿的问题?
经常听有人说,使用MVVM就能解决ViewController过重的问题。其实我觉得这是一个伪命题。就像前面分析的那样,MVC本质就是三层框架思想,Controller是一个层级,它不是指某个类,简单说就是ViewController不等于C,它只是C的一部分。对于ViewContrller臃肿的问题,我觉得不能归咎于MVC的问题,实际如果我们的代码不进行模块化,你的View、Model层、也包括你使用MVVM的VM层都有可能出现臃肿的问题。所以本身某个类出现代码臃肿的问题不是因为你使用了什么框架,而是你怎么编写代码的问题。
不管所谓的MVC、MVP或者MVVM,它们其实就是一种分层思想,将代码结构按层次进行划分、然后通过中间层进行解耦。目的只是在于层间解耦,并没有强调某一层由某个类来实现。不同的层内部又可以按照业务需求分成不同的模块,不同的模块又可以分成不同子模块。就像前面说过,在iOS中使用MVC,不要把C层等同于UIViewController及其子类,C层可以不止包含ViewController,还有可以有其它的类来分担。
说到这里,顺便说一个问题。为什么在iOS使用MVC很少有人说View臃肿或者Model臃肿?这其实很简单,因为习惯上我们在面对复杂View的时候一般都会把View层分成不同的子View来实现,这其实就是一个很好的模块化的例子。Model层也一样。但是Model还有一个问题,就是很多人经常把数据模型Model误认为是MVC的Model层,导致的问题就是仅限于把M当做数据层,但是回过头来看的话,M层在MVC中的定位是业务层,它是负责保存应用程序的数据并定义操作该数据的逻辑,然后将数据交给View层展示的。如果我们仅仅把M层当做数据层的话,那么就容易少了一个定义数据操作的业务层,所以就出现了我们前面说的,在iOS中很多人把业务层代码都写到ViewController导致臃肿的问题。
在iOS中使用MVC的一些代码实践
ModelController
针对iOS的MVC中,因为ViewController的角色合并导致在使用上出现混淆的问题,与之相对应创建一个ModelController对象。这个ModelController的定位具有了部分Model和Controller的功能。
这样我们就可以把ViewController看着主要关注View层的Controller,它"拥有"View,管理View相关的逻辑以及View和Model的通信;而ModelController是一个主要关注Model层的Controller。它“拥有”Model,负责定义Model的相关操作方法,把数据交给View层展示,并可以根据View层的事件操作Model。
代码结构分析
根据前面的分析,在代码编写时,我们采用了如下图所示的结构:
这里View层和Model层原来的角色不变,我们把Controller分为ViewController和ModelController两个部分。
- ViewController是页面得基本单位,管理者当前页面相关对象的生命周期,包括View和ModelController对象,正常情况下每个页面一个ViewController,每个ViewController可以拥有多个View,同时一个ViewController拥有一个或多个ModelController;
- ModelController用于管理当前view的需要显示和操作的Model,一个ModelController拥有一个或多个Model,ModelController持有View需要展示的数据,通过ViewController交给View显示。