三层模式
一般的iOS教程,都是MVC,从界面到数据,一次搞定。从网络读取数据,然后根据实际情况,将数据处理一下,就在界面上显示。M是指数据,一般都是类型定义;VC一般都在controller中实现,特别是代码写界面的实现。这样就导致controller任务很重,几乎做了所有的事情。所以,iOS一般不需要架构,因为controller几乎可以一步到位,而MVC的概念又足够简单,无需再分层,只要考虑如果分模块,分任务就可以了。这就是现状。
iOS中的MVC看起来是三层,但是在现实中就是一层,一步到位。在现状的基础上往前走一小步,就是我们现状考虑的iOS架构。目的有两个, 一个是分三层,让理念和现实更接近,就分三层先固化下来。另一个是降低controller的复杂度,将界面,逻辑,数据处理的内容都分离出去,只保留调度者的作用。在分层中,将view和controller都分到界面层,因为view不能离开controller单独存在。在这里controller就相当于一个大总管,不做具体的事,一方面让view有展示的机会,另一方面,让逻辑层函数有表现的机会。
iOS开发绕不过的两个交互界面,一是产品和设计,特点是多变,而且变的成本很低;二是后台MTP,特点是基本上不愿意变,变得也很慢。等这两者都差不多了,才轮到iOS开发自己,那个时候就发现压力全来了,前面等,浪费很多时间,现在加班也来不及。为了解决这种被动局面,可以考虑把当前MVC一步到位的模式分为界面,逻辑,数据三部分。界面跟设计对接,数据跟后台MTP对接,这两层都尽量薄,不需要太多考虑复用的问题,胶水代码或者尽量不用代码,关键是应对要快,改起来方便。逻辑层,尽量大,尽量能复用,模块可以分得多,分得细,降低耦合度,并且随着业务发展,可以沉淀出很多自己独特的内容。
-
界面
界面开发一直有IB和代码的争论。对于IB,合作开发,影响性能是一直被诟病的两点。就像当年的ARC和MRC的争论一样,双方都有道理,也不需要有对错,完全是选择而已。所以,我们的选择很简单,遵循苹果推荐的方式,采用IB,并且用storyboard,sizeclass,imageset等最新的概念。合作开发,代码管理,影响性能之类的都是伪命题,都不是我们所关注的重点。
界面开发的第二个重点是把显示逻辑抽出来,交给view model;将业务逻辑抽出来,交给独立的logic模块;将数据部分抽出来,交给各个data source;controller中只保留不得不保留的部分,最轻量级化。controller很难复用,所以能有多简单就做得多简单,不准留一点非他不可的东西。
界面开发的第三个问题是view的复用。这块的主流和习惯也是代码写组件,这没什么不好,也是一个价值观的问题。提高代码质量的最好办法就是没有代码,所以很大一部分的组件可以用xib直接实现,用起来也方便。至于动画和动态界面部分,目前只能用代码来实现,就用代码来做。
这一层的比重,最好不要超过25%,并且代码越少越好。 -
逻辑
iOS程序崩溃有80%出现在是否为空,即nil上面。界面元素,一般都是非空的,不显示,可以用view的hiden属性来表示,也可以用字符串的“”来表示。一旦碰到空,也就是nil,就有崩溃的危险。但是网络来的数据,一般都是可能为nil的。就算业务规定某个字段不能为空,比如uerID,但是实际中,网络都不通,对客户端来说,就是nil。如果程序开发时不考虑这一点,那么就有可能开发时什么都正常,但是实际中就是不断有崩溃。从这个角度来说,将逻辑层单独列出来,专门处理“数据层所有字段都可能为空;业务逻辑上,有些字段可能为空,有些字段不允许为空;界面上,所有字段都不能为空”这种情况,也是非常有意义的。
页面和页面跳转,交互可能变化比较多,但是在业务逻辑上,可能改动很少或者基本可固定。另外,界面的分类标准和业务逻辑上的分类标准很可能不一致。比如有些复杂页面,涉及到的逻辑层面很多,但是也有好多页面,都属于一个业务逻辑概念。从这个角度讲,将逻辑层单独出来,按照业务标准分模块,尽量考虑复用,也是很有价值的。
这一层的比重,最好能够超过50% -
数据
数据层的考虑问题方式天生跟逻辑层不一样。比如,对iOS程序来说,网络API是肯定逃不掉的。首先考虑的问题是自己写还是用第三方库;用http还是用tcp长连接等等。所以,数据层是按数据方式作为第一维度考虑的。此外,还有数据库,也就是本地缓存,稍微大一点的app都是绕不过的话题。所以数据层的第一步是按照数据来源和存储,操纵方式分模块。
第二层次,才是按照功能分模块。这里的建议是数据层尽量把重点放在数据操纵上面,逻辑方面的内容少涉及。就把数据层当个二传手吧,能把数据传输和存储搞好就可以了。至于数据的逻辑意义,交给逻辑层处理。
这一层的比重,最好不要超过25%
从MVC过渡到MVVM
- 借鉴MVVM的思想,但是不完全遵循MVVM规范,比如双向绑定就太复杂
- 不引入ReactiveCocoa,因为增加了复杂度和学习成本
- 界面层可以包含storyboard,xib,view,controller,view model;尽量薄,尽量少用代码,和UX人员协作开发;只包含显示逻辑,不包含业务逻辑
- 数据层尽量薄,只做“传声筒”,将json字段简单地转换为自定义数据类型。只负责把数据从服务端拿到本地,不负责解释数据的意义;和后台人员一起根据API接口来实现。
- 调用接口由界面、数据两层定义,逻辑层负责将这两层的接口打通,形成落地的闭环。其他不能放在界面、数据两层的内容都放在这一层统一规划。
从Cocoa Pods过渡到 Carthage
- 抛弃.a .bundle 方式,统一采用framework方式
- 只使用编译好的framework模块,不需要重新编译
ViewController瘦身
- 不准作为delegate
- 不准有自定义的base controller,不准有自定义继承
- 不准作为data source
- 不准复用
- 不准作为函数参数传递
文件命名
- 主动采用workspace模式,并且workspace的名字和project的名字可以不一样
- 不准有public、common、base等语义不明确的文件夹
- 界面层按页面跳转分模块,逻辑层按业务逻辑分模块,数据层按数据来源或数据存储方式分模块
网友评论
“ViewController瘦身
不准作为delegate
不准有自定义的base controller,不准有自定义继承
不准作为data source
不准复用
不准作为函数参数传递”
有比较详细的解释吗?
delegate 和 dataSource是对表格而言的,一般用ViewController最方便,这里建议用和表格同一级别的ViewModel来做。
Base Congtroller就是基类,完成一些基础工作;在Swift中可以用协议,并扩展协议提供默认实现来达到同样效果。
vc做函数参数,比如调用照相机的系统函数,这些就用吧。但是自己就不要设计让人传vc参数的函数了。
ViewController太重要了(AppDelegate也一样),代表了生命周期,发起和结构都靠它,它也很能干,什么都可以做。所以,才考虑给它减负,让它做个“司令”就可以了,具体的事交给其他的来做。
当然,实际开发中,什么都在ViewController中做也是可以的,现实中也普遍是这样的,能达到目的就可以。
这方面,推荐唐巧的 MVVM 以及 猿题库架构设计 等文章,写得还是不错的
Carthage
只支持iOS8以上,iOS7放弃了?