基于数据驱动模式的UITableView解耦方案

总述

  1. 传统的TableView是在一个又一个协议的驱动下构建的。一方面,每次我们都要重复的实现逻辑类似的协议,另一方面,业务逻辑不可避免的耦合到了numberOfRows,heightOfRow,cellForRow这些方法中,难以维护。
  2. 本文方案的核心思想是抽象封装UITableView的数据源,通过构造特定的数据源来驱动TableView的创建。

问题引入

场景模拟

假如有一个类似网易云音乐首页的页面,根据UI图判断,从上到下分别有轮播图、今日热榜、流行音乐、为你推荐4个section。传统的思路,我们可能会为相应的section建立枚举,然后写出类似如下风格的代码。

switch(type){
    case banner:
    case hot:
    ....
}

复制代码

这段代码至少会在数据源方法里出现3处,返回height时,返回rows时,返回cell时。但总之,我们确实实现了需求。

接着来到了第二版迭代,产品提出需求希望在banner下面加一个新栏目。此时,我们可能先在枚举里加新的值,然后在3个协议方法里插上新的代码。感觉到没有,后面每增删改一个模块,都需要这么修改,如果加上cell的事件回调,将是很庞大的一坨代码。

接着来到了最后一版,产品说我们又这么多模块了,干脆像网易云音乐一样,用户可以自己定制要显示哪些模块,而且这些模块位置可以自由排序。你会如何修改呢?

问题分析

上述问题的核心原因其实出在tableView的数据源上。传统思路中作为数据源的models都只是接口字段的映射,而tableView的数据源除了属性外,还需要知道height、reuserId等信息,这些合一起才是合格的tableview数据源对象。否则,这些信息就需要我们临时给出。比如在返回cell时,我们那一堆判断逻辑就是为了临时给出reuserId这个信息,然后结合Model组成完整的数据源信息。

方案设计

抽离数据源

分析后,其实我们的方案思路已经很清晰了,首先抽象出一个通用的cell对应的数据模型Item,Item包含了height、reuserId、data(对应json模型)等信息。之后,我们就可以从具体的controller中抽离tableView数据源了。

此时数据源逻辑是模板化的,numberOfrows的方法中返回items.count,cell的方法中从item取reuserId并返回cell.在这里,我们一般要根据model调方法更新cell的视图,这里我们怎么抽象出这个方法呢?可以通过协议抽象cell必须遵守的方法。

顺着这个思路完善下去,除了抽象row对应的模型外,我们还可以抽象section数据模型,一个sectionObject持有items可变数组,headerHeight,footerHeight等信息。一个customDataSource对象持有sections可变数组。最后,在具体的页面中,基本上就是下面的代码风格。

customDataSource.sections = sections;
self.tableView.dataSource = customDataSource;
复制代码

构造tableView时,我们从关注各种代理方法变成了专注于数据,通过数据驱动UI逻辑。回到最初的场景,此时决定哪个音乐模块在哪个位置显示,仅仅取决于他在section数组中的索引。

基于响应链的事件传递

我们已经成功的抽离了数据源,还有一个问题就是原先耦合在cell中的回调事件如何处理。比如登录注册界面,我们往往需要从cell中往controller回调textDidBegan,textDidChanged等。现在cell的创建过程都已经抽离并且隐藏掉了,那这部分逻辑要如何实现呢?

方案是通过响应链来实现cell往controller的事件传递,灵感来源于casa的基于响应链的对象交互方式

详细方案可参考demo:tableView解耦

欢迎评论、投硬币、投香蕉 ^_^

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值