事情从一般开发中一个massive viewController说起,一个巨大的vc一般少则上千行代码,多则上万行。
这中情况下对代码的维护有致命性的障碍,个人亲身体验。
当你试着从6000行的代码中去找到一个网络请求,找到相关的实现逻辑,这已经能够让你眼花缭乱的。
更进一步,如果你打算对某个逻辑,某个场景进行测试,那事情的困难程度非常大。
再者,如果你想重用某一部分的场景逻辑,那几乎不可能,因为所有的代码都耦合在一个vc中了。
为什么会造成一个vc的代码这么多,这么复杂呢?
一般有以下原因:
1.view的构建:不管是用IB还是手写界面,初学者一般是将界面构建的代码放在vc中,甚至在vc的生命周期函数中,这是踏出massive viewController的第一步。
2.网络数据的请求及后续处理:网络请求是一个比较关键的地方,涉及到数据的处理。我们在MVC模式下做个讨论,首先是View,View作为界面实现对象,一般能够用MVC的人不会把网络请求放里面了,这个跳过。接下来是model,一般MVC中model作为模型实体类,用于存放实体信息,执行实体的某些行为,本地数据库的操作,如果把网络请求放到model中执行,网络数据需要异步执行,如果model生命时间比网络数据请求时间长,那还可以,但是一般的服务器返回json数据中包含的实体信息非常多甚至一些无关model的请求,这部分又是一个问题,所以model里做网络显得格格不入,最后只能用vc,这是massive viewController的第二步。
3.响应逻辑:在vc中常常会有对用户事件作出的相应代码以及delegate方法,这部分代码中往往包含着复杂的判断逻辑及数据处理代码,这是massive viewController的第三步。
4.数据源方法:典型的tableView会有datasource方法,其中数cellForRowAtIndexpath最为典型,其中数据展示前的代码也是非常多,massive viewController的第四步。
5.本地数据库操作:不多解释,massive viewController第五步。
6.其它无关vc的代码:其它的比如有点工具性质及其他的代码。于是66大顺,一个massive viewController形成。
上面列举这么多原因,无非想说明一个massive viewController的由来,就像剖析一个人的成功经历一样。
那么接下来重点就是如何解决这烦人的massive viewController了,为了实现一个轻量级viewController。
既然有原因,那么解决办法就从原因入手吧,先后顺序不定,结合MVC模式(Model+View+Controller),不懂的自行google。
1.view的处理:个人愚见,一般的做法是从vc中分离出一个主要的view类,如果view类中有其他的复杂的view,那么继续向下分离。我们可以模拟UIKit的做法,一个原则就是大的view构造成像tableView等视图一样,小的view构造成一个控件如tabbar之类,再把相关视图可能做出的点击效果和实现逻辑封装在类中,留出接口,定制一些协议,执行代理方法数据源方法,这样的话不仅减轻了viewController的负担,而且还大大提高view对象的封装性及可重用性,比如你想在不同的vc上使用同一个view,那么你不用再去重写,只需根据已有的接口和代理,数据源方法来实现相关逻辑即可。
2.网络数据的处理,这个放后面的MVVM讨论。
4.数据源方法:继续分离vc的职责,分离出功能单一的dataSource,再把相关的数据传递过去,相关的处理逻辑block传递过去。其他的数据处理部分照样留下面MVVM介绍。
5.本地数据库操作:在MVC模式下,这部分代码应该封装到model中,在vc里调用相关接口即可。
3.响应逻辑:经过对view的封装,相关的响应方法已经比较清晰,但是其中的响应逻辑还未处理,其实无非是对数据进行处理,因为视图展示效果已经封装到view类中了。对于本地数据的操作可以调用model的方法进行操作。
6.对于一些无关vc的代码,如果可以重用,那么应该在项目中添加在Util目录中,以做工具类使用。
接下来介绍MVVM模式,MVVM = Model + View + ViewModel,当然在iOS中还有一个viewController。
相比起MVC,MVVM多了一个viewModel,而重点就在于viewModel。
顾名思义,viewModel即视图模型,对视图展示数据进行处理,一般流程是,接受vc的事件命令请求及处理相关数据,完事之后将标准展示数据处理好交给vc展示到view上,此谓视图模型。将视图模型分离出来,与视图类做法类似,留出操作接口,协议及代理,这样一来,对于数据层又可以重用,只要vc符合相关的协议,那么在不同的vc中就可以用同一个viewModel了。封装性和重用性得以体现,而且便于测试。
借用歪果人的回答就是:
Views display a certain shape of data. They have no idea where the data comes from.
ViewModels hold a certain shape of data and commands, they do not know where the data, or code, comes from or how it is displayed.
Models hold the actual data (various context, store or other methods)
Controllers listen for, and publish, events. Controllers provide the logic that controls what data is seen and where. Controllers provide the command code to the ViewModel so that the ViewModel is actually reusable.
这样一来,我们可以把数据有效性的验证,视图的展示逻辑,网络数据请求及处理,其他的数据处理逻辑集合到viewModel中。
上文中的问题得以解决:
2.网络数据的处理:在viewModel中构建相关网络请求逻辑并将加载完的数据进行处理及本地保存,用代理方法通知vc执行数据展示。
4.数据源方法:在viewModel中我们可以构建一些接口来封装heightForRowAtIndexpath,numberOfRowInSection方法里的展示逻辑,进而把validation data的代码封装起来。
5.本地数据库操作:作为连接model和vc的中间枢纽,本地数据库的操作应该封装到viewModel中的数据处理逻辑上。
MVVM的介绍及解决massive viewController问题大概这么多。附上一些介绍链接:
objc.io,http://www.teehanlax.com/blog/model-view-viewmodel-for-ios/
说了这么多,说点总结性的东西。
MVC和MVVM的区别和共同点。
区别:
优点:MVVM就是在MVC的基础上加入了一个视图模型viewModel,用于数据有效性的验证,视图的展示逻辑,网络数据请求及处理,其他的数据处理逻辑集合,并定下相关接口和协议。相比起MVC,MVVM中vc的职责和复杂度更小,对数据处理逻辑的测试更加方便,对bug的原因排查更加方便,代码可阅读性,重用性和可维护性更高。MVVM耦合性更低。MVVM不同层级的职责更加明确,更有利于代码的编写和团队的协作。
缺点:MVVM相比MVC代码量有所增加。MVVM相比MVC在代码编写之前需要有更清晰的模式思路。
共同点:
优点:都有Model,View,ViewControlelr三个基础层次,对于视图封装都比较好。都有一定可阅读性。都低耦合性。都有利于代码的维护。各部分的职责分明,便于测试,将大的解决方案化小,有利于团队相互协作。
缺点:所谓的MVC和MVVM没有很明确的定义,在不同平台上更是如此,一千个人有一千个MVC和MVVM的理解,造成理解的困难。代码相比以前会有一定量的增加。
本文总结:
打造一个轻量级的ViewController从Massive ViewControlelr 问题说明出发,剖析原因,再提出对vc进行职责分离,如分离出model,dataSource,Util工具等,再到MVC中讨论问题的解决办法,进而到MVC的升级版MVVM的问题解决思路。总体上,一个轻量级的ViewController构造思路是这样,存在既有道理,MVC和MVVM有优点也有缺点,但缺点在他们所带来的好处面前时不值一提的。他们的低耦合性,封装性,可测试性,可维护性和多人协作便利大大提高了开法效率。
一句话总结就是,一个轻量级的ViewController是基于MVC和MVVM模式进行代码职责的分离而打造的。
时间有限,代码就不贴了。
相关参考和链接附上
1.objc.io
2.http://www.teehanlax.com/blog/model-view-viewmodel-for-ios/
3.stackoverflow:different between MVC MVVM, advantage of MVC,advantage of MVVM
4.github:C-41,MVVM模式的开源项目