问题
由于原来首页列表需求多次大变动,加载cell
的逻辑也跟着调整了很多次,cell
的种类以及布局也变化很大,这次刚好进行重构;而且,原来的加载方式会大量进行子视图修改,有一定的潜在性能问题.
需求分析及目标
cell
布局更加灵活,以后增加新类型不需要修改控制器代码逻辑,简言之,视图和控制器解耦;- 实现代码复用
- 解决潜在性能问题
在进行coding之前,可以参考一下几篇文章,里面对列表的论述多有裨益:
更轻量的 View Controllers
整洁的 Table View 代码
iOS 保持界面流畅的技巧
前两篇介绍了如何编写低耦合的UITableView
代码的思想,核心就是:
- 将其
delegate
和datasource
进行独立,创建单独的类进行管理,这个类是可以复用的,并且通过blocks
的方法进行cell
的创建于赋值,而控制器不需要了解cell
的实现; - 将数据操作集中到单独创建的类中,而数据模型有时候携带的数据还需要重新加工才可以使用,例如返回
yyyy-MM-dd HH:mm:ss
类型的时间,而我们需要的是yyyy年MM月dd日
格式的字符串,类似这种处理可以放在模型的category
中; - 面对复杂的布局,比如当前页面中会显示多个控制器视图,类似
UITabBarController
结构,我们可以采用加载Child Controller
的方式,将内聚程度高的代码写到所属控制器中;
这样,基本上就可以写出比较好,易于测试的UITabelView
了,具体的代码可以参考原文,讲述的很详细了.
第三篇博文主要讲解了如何进行性能优化,总结下来就是以下几点:
- CPU耗费资源的地方主要在
对象创建
,对象调整
,对象销毁
,布局计算
,Autolayout
,文本计算
,文本渲染
,图片的解码
,图像的绘制
等; - GPU资源的耗费主要集中在
纹理的渲染
,视图的混合
,图像的生成
针对以上几个方面,作者一一给出了解决方案,详细内容请参看原文
值得注意的是作者提出了过早的优化是万恶之源
,当需求不明显或者性能问题不明显的时候尽量不要尝试优化,并给出了评测界面的方法,开源了一个查看FPS
的小工具,地址戳一下
作者开源了一个开发套件,非常不错,里面附了一个微博的Feedlist demo,代码写的非常漂亮,准备借鉴他的做法,demo地址
实践
看一下页面列表,大概是这样的:
首页返回的简化数据结构:
现在cell
至少有两种布局,一种根据list
显示若干item
,一种显示为text
,根据上图可以将 cell 划分三部分:
- 顶部显示标题,包括姓名以及指标的名称,未读数,日期,分割线,实际上还有一个诊断的按钮, UI 上没有显示,诊断和标题有点击事件;
- 中部根据返回的数据类型,显示为文本或者若干 item, item 最多显示6个,并且可能有点击事件;
- 底部显示箭头,阴影以及一定的留白.
首先,定义一个DHHomeCell
类,用于显示所有的数据类型,在主页中进行设置;
接着,定义一个DHHomeLayout
类,用于在子线程计算cell
的布局等耗时操作,cell
通过layout
对象进行对象绑定,高度设置;
最后,定义一个DHHomeCellDelegate
,用于传递点击事件.
这样,就把视图,数据处理以及交互进行了分离.
cell
中大概是这样的:
所有的视图都通过layout
的计算结果进行布局,当为list
样式,cell
中的HDNewDataItemView
个数不确定,类似的,根据常见的九宫格布局,可以在初始化的时候一次性添加 6 个这样的子视图,默认全部隐藏,然后根据返回的list
进行显示.
在DHHomeLayout
中,可以定义一些处理好的数据以及计算的frame
作为属性,方便进行缓存处理,实现大概是这样子的:
需要注意的是,其中一些属性,比如图片相关的设置,是需要在主线程中进行的.一些经常使用的图片或者创建耗时的对象可以使用dispatch_once
代码块进行保存,都可以进行一定的性能优化,如果还是出现卡顿,确定问题后,可以借助开源的异步显示框架进行优化.
调用起来大概是这样子的:
这样,基本完成了复杂列表的重构.
还可以创建一个工具类或者category
,将常用的处理方法进行封装,使用工具类处理,可以方便测试以及代码复用.
如果以后需求出现变动,只需要cell
添加新视图,layout
计算新的视图的布局,增加新的枚举类型即可完成布局.