我是不敢轻易谈MVVM架构设计的
终于在经过前面几篇文章内容的铺垫之后,现在简单说说自己的想法
切记,如果没有kvc kvo的原理知识铺垫,最好去复习一下,否则看过了解,回头就会忘却,不会形成意识
KVC原理
KVO原理
iOS架构设计(一)- MVC
iOS架构设计(二)- MVP
再次提醒:务必去了解一下 kvc kvo原理
因为我在文中MVVM的架构设计会依赖自定义KVO机制去实现
MVVM也会基于之前的 iOS架构设计(二)- MVP 去实现,所以没有看过的同学建议还是先出门阅读下
MVVM的本质
首先 架构设计更新到MVVM,是在MVC MVP KVC KVO的基础上发展而来的,我计划用前面的内容来成就MVVM,而不会增加新的内容,更不会平白无故的增加额外的管理类什么的
否则 前面几章铺陈就变得毫无意义可言 那这篇文章就如同行尸走肉一般 而我就是全身腐化气质了,我并不想那样
可能人各有偏好,我不理解的是 我看过一些别人写的MVVM,个人觉得没有特别适合我的,不知道是block炫技 还是秀delegate,思想我是get到了,可代码凌乱不堪,我考虑的是 我用这样的设计,怎么跟别人协作项目,我心里是没信息
争取我在此篇文章里阐述的能使我自己不迷糊,如能触碰到你心里的点,这篇文章的价值才出得来
先看一张图
这是我看到的一个利用MVVM的项目,我整理了下设计流程
图中的意思我简单概括下
一个vc创造一个manager,manager呢功能很强,因为遵从3个协议,也就是把控制权交给了manager,但是这样的操作跟VC本身做又有什么区别
manager通过viewModel作为delegate 调度viewModel去管理view
viewModel又通过 manager遵从协议 驱动一些其他类,而且还是关联对象存储
viewMode又通过数据更新渲染view
。。。。。
反正 我看到毛毛多的block,block泛滥,不是排斥,只是这种block爆发蔓延,看上去挺高大上,反正很快要抓住主干思想脉络 我是做不到的
我按照这样的架构设计去安排我的代码,图中的很多线我都需要考虑,不得不考虑,环节对不上,我的视图可能就刷新不起来;
而且很多关系是靠代码逻辑演化出来的,也就是我没办法从顶层设计上确切知道我未来的代码走势,复杂度会演化成什么样子,我都不知道
我自己没那个信心 能践行得很好,从项目角度上讲,我自己在这个架构设计下,是没有把控能力的
总之 我觉得是很乱,如果让我选,我毫不犹豫选择我之前设计的那个MVC,比这个好用,功能也不弱,协作起来问题也不大
回到正题
回到从MVVM最本质的思想
这张图的意思很明了,就两根线
一根 View <-> viewModel
一根 viewModel <-> Model
如果这篇文章里我们能解决这两根线,基本上就算实现了MVVM
除此之外,为了达到这个目的,我们的其他嫁接配置部分代码不应该侵入这两条线
这个思想很纯粹,很精辟 (ViewModel可以理解为一个大圣人,无所不能)
视图通过 ViewModel来渲染 不管是主动的还是被动的,反正就一条线;
视图的交互状态提交给 ViewModel;
Model通过ViewModel来交付;
Model本身的增删改 同步给ViewModel
接下来 我会按照上面的两条线的解读来设计
MVP的底子
会不会有人有疑问呀,这是骗人的吧?????
那么多代码,就这几条线,糊弄的吧。。。。
我相信会有人在心里这样犯嘀咕
因为很多工作包括配置是在基类初始化中完成的,所以我画了两条虚线,VC构建了两个重要的角色,View和Presenter
而这些基类跟配置属于万年不变的类,它的配置调试只属于架构者,项目定式后,可以选择作为库,项目中的其他成员是不涉及的,剩下的工作就是依赖那两条实线了
那对比一下上面MVVM的那个思想图
我把最右侧的那条
弯弯虚线
变成实线
,给View添加观察者Adapter,
给 Adapter添加观察者 Presenter,
这样就变成两条 双向的线,
而且我把Adapter换成一个神奇名字 -- ViewModel
Presenter可以换成 Model,不过从职能上来将,我还是觉得Presenter更合适
我就基本上把之前的MVP改造成了一个MVVM架构,
更确切的说,是 PVVM, P就是Presenter
这可能么,我倒不存什么疑问,最起码我是按照MVVM的设计思想来调整的我的MVP,不觉得有什么冲突的地方
从MVP处拷贝一份代码出来
首先这份mvp架构设计的代码是没问题的,只是我把关键字 list 替换成了 list1
接下来就是我们魔改了
adapter我打算沿用,名字不做更改,主要还是为了方便对比 MVP
给图方便描述修改过程,我把MVP原理图上的线给编上号
MVP调整过程
去掉线3
分两步
presenter驱动view刷新 变成了 adapter的责任
现在代码 按照图中 线的变化 调整,去掉线3,增加线6
由于线3去掉了,则View的渲染驱动就没有了,此消彼长,在别处也就是adapter补上
你会发现在adapter中 一句关键代码 [self needRefresh] View刷新渲染数据
目的是达到了,有点粗糙
可以先看下原因
其实就是View作为adapter的观察者,被动刷新渲染
MVP的架构设计只改了一点点,目前列表数据加载都是正常,加减操作 逻辑没有受任何影响
添加View -> Adapter 的一条实线
线5我画的是虚线,所以不用管它
不用改代码,线自然就补充上来了,就相当于 View触发 执行了一个同步流程,View也就拿到了返回值,刷新
这条线的添加就不用改代码了
顺便 Adapter -〉 Presenter 那条线也就有了
由此,MVVM也就改好了,我更习惯称之为 VAP, 也就是 View - Adapter - Presenter
Adapter 就是ViewModel Presenter就是Model
这种设计就是个双向的管道, 一头是View,一头是Presenter
Presenter是数据的源头,自然而然从Presenter流入View,期间经过Adapter
View最终是要把数据渲染到视图上去的,状态的变化自然要回溯到源头Presenter,中间也经过Adapter
比预想到修改要少好多好多,因为MVP中有一个context的设计,所以目前这种架构设计还可以再调整,
得益于灵活的context设计
你会否觉得与你预想的不一样,感觉文章就没说头,反正对我而言,设计就这些,更复杂的代码在此基础上 不会变得烦乱不可控,有凌乱的也只会是在局部,不会在整个设计中蔓延开来
我平时就是这样来控制的,不是说细节做到尽善尽美,也有瑕疵的地方,但不影响大局
还有一部分没拿出来说明,就是这个设计架构本身有些业务代码是来自工程编译本身产生的,
那是因为在这个设计里设定了一些规则,一些职能类的命名规范,还有功能流转方式是可以被这个架构设计严格限制的
这样即便项目庞杂了,想堆代码是不可行的,堆代码只会影响自己的业务本身,不安规矩来的话,就会发现代码根本是跑不通的
进一步抽象 改名
代码改到这个地步,感觉根一般见到的MVVM一点都不像,没关系,我们继续
抽象出一个baseview
- 把订阅放到VC的配置阶段
- View中去掉订阅逻辑,通用的订阅逻辑交由base
如此,View 与 ViewModel之间就从代码层面上看出订阅关系了
View与ViewModule的业务绑定
同样 这些也是base处理的,View本身透明
View订阅之后,剩下的就是
数据的整体刷新到来,响应刷新
根据订阅的自定义类型,局部处理
这里不选用block,是因为用block会在View里多了一些不必要的配置,不够纯粹,当前的方式 只需要处理这两个方法就可以了,而且换个模块 方法名也是固定的,基本上View里的代码个是就是固定的模板了
涉及的代码部分,同样可以从 github 获取