非常感谢 Casa 老师的文章,让我长久以来的很多疑惑,很多看了又忘的知识得到了系统的整理和总结。文章很容易让我建立起自己的记忆模型。就我的感觉,作为iOS程序员,把这样的文章读上几十遍都不为过,有种醍醐灌顶的痛彻。其中还有一个很重要的点,作为架构师是为工程师服务的,这种想法尤其的纯粹,放到工程师身上,如果也想着自己的代码是给别人读的,自己的产品是给用户用的,相信世界将变得更美好,我们离梦想也会更近。
View代码结构的规定 -- life cycle --> delegate --> event response --> getter & setter ❤❤❤
关于view的布局 -- masonry ❤❤❤
何时使用storyboard,nib,coding
统一派生ViewController? -- AOP ❤❤❤
方便View布局的小工具
MVC、MVVM、MVCS、VIPER ❤❤❤
跨业务时View的处理 -- Mediator ❤❤❤
1. Coding Guidelines
2. VC结构
(1) 图
(2) ViewDidLoad --> addSubView
(2.5) viewWillLayoutSubview or didLayoutSubview --> 布局
(3) ViewDidAppear --> Notification,通知一类
(4) 属性初始化 --> getter & setter(or [self ~~])
life cycle --> delegate --> event response --> getter & setter
3. View布局
Masonry (UIView + LayoutMethod + AEBHandyAutoLayout)
4. Storyboard + nib + coding
(1) 改动
(2) link现 的 + -
5. 统一派生VC
(1) 使用成本
<1> 集成成本
<2> 上手成本
<3> 架构维护
(2) 不使用派生也可以
AOP --> Method Swizzling(Aspects) <1> VC拦截 <2> NSObject的+load
Method Swizzling只支持针对现有方法的操作。
拓展方法 --> Category(化继承为组合)不推荐过度使用
6. MVC
<1> MVC(Model - View - Controller):
其中Model是数据管理者,View是数据展示者,Controller是数据加工者。Model和View又都是由Controller来根据业务需求调配,所以Controller还负担了一个数据流调配的功能。
在 Cocoa 的模型-视图-控制器 (Model-view-controller)架构里,控制器负责让视图和模型同步。这一共有两步:当 model 对象改变的时候,视图应该随之改变以反映模型的变化;当用户和控制器交互的时候,模型也应该做出相应的改变。
<2> 服务器端 & Native(图)
UIViewController --> UIView(容器)(再看objccn的VC教程豁然开朗)
<3> 在iOS开发领域中,MVC划分
M:
给 VC 提供数据
给 VC 存储数据提供接口
提供经过抽象的业务基础组件,供 C 调度
C:
管理 VC 的生命周期
负责生成所有的 View 实例,并放入 VC
监听来自 View 与业务有关的事件,通过与 Model 的合作,来完成对应事件的业务
V:
响应与业务无关的事件,并因此引发动画效果,点击反馈(如果合适的话,尽量还是放在View去做)
界面元素表达
<4> MVCS
拆分的部分是 Model,拆出来一个 Store,专门负责数据存取。实际是拆分C。
7. 胖 Model && 瘦 Model
(1)胖 M包含了部分弱业务逻辑。目的:C从胖M这里拿到数据之后,不用额外做操作或者只要做非常少的操作,就能够将数据直接应用在View上。
强业务变动的可能性要比弱业务大得多,弱业务相对稳定。弱业务重复出现的频率要大于强业务。
缺点:相对比较难移植,拔出萝卜带出泥。违背MVC思想,Model是一个Layer,不应该做Object做的事情。软件成长,越来越胖,难维护。
(2)瘦 M只负责业务数据的表达,所有业务无论强弱一律给C。目的:尽一切可能去编写细粒度Model,然后配置各种helper类或方法来对弱业务做抽象,强业务 --> C。
缺点:一定程度违背了DRY的思路。C会膨胀。
MVCS是基于瘦Model的一种架构思路,把原本Model要做的很多事情中的其中一部分关于数据存储的代码抽象成了 Store,在一定程度上降低了 C 的压力。
8. MVVM
把数据加工的任务从 C 中解放了出来,使得 C 只需要专注于数据调配的工作,ViewModel则去负责数据加工并通过通知机制让 View 响应 ViewModel的改变。ViewModel就是把RawData变成直接能被View使用的对象的一种Model。
MVVM是基于胖Model的架构思路建立的,然后在胖Model中拆分两部分:Model && ViewModel。
reformer == ViewModel -- API -> View方向
ReactiveCocoa的RACSignal -- View -> API & Con方向
8.5 ReactiveCocoa
不用RAC也能MVVM,用RAC能更好地体现MVVM的精髓。前面的例子是 数据从API到View的方向,View的操作也会产生数据,数据更多体现在表达用户的操作上,比如输入内容,就是text,选择cell,就是indexPath。那么数据从View走向API 或者 C。就是RAC发挥的地方。
View <--> ViewModel <--> Model
View <--> C <--> ViewModel <--> Model = MVCVM
C夹在V 和 VM之间,是将V 和 VM进行绑定。逻辑上,C 知道要展示哪个View,也知道应该使用哪个VM,但是V和VM互相不知道对方。所以要绑定。
在MVC的基础上,把C拆出一个ViewModel专门负责数据处理的事情,就是MVVM。还有一种说法是本身有胖Model,用于处理弱业务逻辑的事情,是对胖Model中数据加工的功能进行了分离。
在iOS领域里KVO,Notification,block,delegate 和 target-action 都可以用来做数据通信,实现绑定。但都不如RAC提供的RACSignal来的优雅,不用RAC,绑定关系可能做不到那么松散。
9. VIPER (View - Interactor - Presenter - Entity - Routing)
10. 拆分:
第一心法:保留最重要的任务,拆分其他不重要的任务。
第二心法:拆分后的模块要尽可能提高可复用性,尽量做到DRY -- IOP
第三心法:要尽可能提高拆分模块后的抽象度
发送文本和图片逻辑 -- 对枚举的应用
即使拆分粒度因为客观原因无法细化,那也能把复杂的判断逻辑和调度逻辑从 C 中抽出来,真正的为 C 做到了减负。总之能够做到大粒度就尽量大粒度,实在做不到那也行,用Strategy把它hold住。
Strategy模式 -- 拆分粒度无法细化,用于处理复杂的判断逻辑和调度逻辑。
10.5 设计:
一:尽可能减少继承层级,涉及苹果原生对象的尽量不要继承
二:做好代码规范,规定好代码在文件中的布局,尤其是VC中
三:能不放在C做的事情就尽量不要放在C里面去做
跨业务页面调用方案的设计
依赖关系下沉 -- Mediator模式
11. objc并没有像java那么严格的私有概念。但在实际工作中,我们并不太会去操作头文件里面没有的变量,这是在规范上就被禁止的。
高度的封装性。getter事实上是工厂方法,有了getter之后,业务逻辑可以更加专注于调用,而不必担心当前变量是否可用。
12. View层架构:
(1)制定良好的规范
(2)选择好合适的模式(MVC、MVCS、MVVM、VIPSER)
(3)根据业务情况针对 VC 做好拆分,提供一些小工具方便开发
13. AOP:
面向切面(切片)的编程,任务一般分为1 2 3 4步,针对每个步骤间隙的编程。
AOP一般都是需要有一个拦截器,然后在每一个切片运行之前和之后(任何你希望的地方),通过调用拦截器的方法来把这个 jointpoint 扔到外面,在外面获得这个 jointpoint 的时候,执行相应的代码。
iOS中,用 Method Swizzling。第二种是使用 protocol。对比MS额外好处是,可以通过拦截器来给实现者提供更多的信息,便于外部实现更加了解当前切片的情况。另外,可以更精细地对切片进行划分。MS的切片粒度是函数粒度的,自己实现的拦截器的切片粒度可以比函数更小,更加精细。
缺点就是,你得自己在每个插入点把调用拦截器方法的代码写上。通过Aspects(MS)来实现的AOP,就轻松一些。