去年作了一个小组件,前些时间考虑到项目中可能会大规模实施,完善简化后新开了一个 repo: YBHandyList 。git
有些朋友抛出了 nimbus、IGListKit 等业界应用很广的库,前些时间网易工程师也推出了 M80TableViewComponent。理论上这些组件的原理大同小异,虽然它们各有优点,但却不太能知足笔者对架构清晰度的要求。github
本文分析 YBHandyList 的应用价值,但愿能解开一些朋友的疑惑。编程
iOS 界面开发中 UITableView / UICollectionView 的出场率极高,它们都是使用代理方法配置数据源,虽然这样的设计理念符合了单一职责原则,但在列表变得复杂时代理方法的处理将变得力不从心:数组
显然,在这样的场景下将是维护的灾难,特别是当你接手别人的代码发现每一个 UITableView 代理方法里都有几十个if-else
,它们人多势众,量你不敢动它们任何一个。缓存
因而可知,若想维护性高须要解开每个 Cell 之间的逻辑耦合,也就是一般意义的模块化,由此才能更轻易的实现动态化。解决方案其实很简单,只须要一个中间类,将分散的配置集中起来(在代理方法里取这个中间类的对应值):安全
@interface Config : NSObject
@property (nonatomic, assign) CGFloat height;
@property (nonatomic, strong) Class cls;
@property (nonatomic, strong) id model;
@end
复制代码
然而对于业务工程师来讲,每次写这样的代码都意味着时间成本,因此制做一个基础组件是颇有必要的,它须要知足如下特性:bash
为此,YBHandyList 应运而生,它足够简单以致于从设计到编码基本就花了一天时间。架构
原理: 模块化
YBHandyList 保留最小功能,代码量不多,核心思路就一句话:将 UITableView / UICollectionView 的数据源从代理方法配置转化为数组配置。编码
在其它库当中能够看到高度缓存、访问迭代器等逻辑,笔者认为这样的基础设施不该该侵入过多业务,它们本应该是业务关注的逻辑,这样的语法糖只能在简单场景下少写些代码,当业务变得复杂时每每这样的优点就不存在了。
YBHandyList 的语法糖很是收敛,简单的一个延展,你甚至能够选择不使用语法糖,直接使用代理实现类。
由此,新手工程师也能对实施代码充满信心。
YBHandyList 采用 IOP 设计,最大限度的下降了业务侵入性,只须要在 Cell / Header / Footer 中实现几个代理方法就好了。
去基类化设计让数据流动过程更加纯粹,不须要考虑父类作了什么,没作什么。在老业务中可能存在相似BaseTableViewCell
的东西,YBHandyList 也能优雅的接入,这种场景下继承的设计范式将力不从心。
这种架构规范类组件接入的成本很是重要,而舍弃的成本也不容忽视,因为 IOP 自然的优点,YBHandyList 结构代码的舍弃将垂手可得,不拖泥带水。
构建界面只须要关注全部id<Config>
在数据源数组中的顺序,就像搭积木同样拼接起来,数组中的顺序就是对应 Cell 在界面中的显示顺序,由此就能经过改变数据源数组的顺序轻易的实现动态化控制。
YBHandyList 的设计方式让它在各类架构中都能无障碍实施,下面以 MVVM 举例(仅说明 UITableViewCell 的实施,具体能够看 DEMO):
能够看到,Cell 与 UITableView 非直接耦合,因此若须要将 Cell 的事件传递出来最好经过 Cell 的 ViewModel,ViewModel 做为链接 Cell 与外界的桥梁。
Cell 的 ViewModel 也能够在主 ViewModel 中构建,这样 Controller 中就不用导入这些类,不过当 Cell 的 ViewModel 须要将事件传递到 Controller 时,就会须要一些胶水代码经过主 ViewModel 间接传递。
数据绑定并不是必须作的事情,你能够用 RAC,或者另一个选择:EasyReact,能够参考笔者的文章:美团 EasyReact 源码剖析:图论与响应式编程。
不少时候,咱们会将具体业务的处理逻辑放 Cell 中或者其 ViewModel 中,那么它们就很难复用,由于复用是创建在无具体业务侵入的前提下。
实际上只须要将具体业务的处理逻辑抽离出来,处理事后再放在 ViewModel 中,Cell 拿到 ViewModel 再进行具体业务无关的界面刷新。如此,ViewModel 将能够在任何地方复用。
使用 YBHandyList 后,ViewModel 把 Cell 与外部业务解开耦合,只把须要暴露的东西写在ViewModel .h
中,外部业务无需导入 Cell 便能经过 ViewModel 直接复用,更加的安全。
一个基础设施最怕的就是不能知足全部场景的状况下还封闭了拓展的入口。YBHandyList 经过继承默认代理实现类就能拓展实现其它的 UITableView / UICollectionView 代理方法。
这看起来有些繁琐,使用多代理技术能避免额外的建立代理实现类,但这样会致使代码再也不简单和透明。换个角度想,代理实现类中将大量复杂逻辑处理事后,仅仅回调给外部业务一个简单的方法,达到为外部模块瘦身的目的。
笔者一直偏好简洁的代码设计,让核心功能最小化实现,当它没法覆盖全部的场景时必定要有原生拓展能力。语法糖的主要意义是减小使用者的思考成本而不仅仅是为了少写两句代码,它不该该侵入功能收敛的核心代码。要作好这一切,就必定要透过现象看清问题的本质。