最近在进行视频直播应用的开发,线上线下在对公聊消息组件进行压力测试的过程中,发现该组件存在以下问题:
- 消息事件频繁触发,频繁绘制导致主线程卡死
- 控件频繁重绘,导致高发消息下卡顿
- 消息控件高度多次计算,多消息下,滑动出现卡顿
为了提高用户体验,针对以上问题,对该组件进行二次开发,以下为一些优化点:
原有组件对公聊消息的处理是收到一条消息则进行一次消息体插入,消息控件reload/insert的操作,这样处理在高并发消息下,会出现频繁绘制导致主线程卡死。因而须对消息调度方法进行一些改进,改进策略上选择用空间换时间,改进步骤具体为:
- 创建消息缓存池,缓存池采用FIFO的策略,每次收到一条消息先进行压栈处理
- 启用定时器,单位时间内对缓存池内的贮存消息定量取出,之后交由消息控件进行刷新渲染操作
- 由于设备硬件特性不同,定时器的单位刷新时间须根据设备类型进行灵活调度,比如iPhone5的单位刷新时间须大于iPhone11
- 实务中,同一时间内消息条数过多,缓存池内消息条数过多,根据业务实际,也可以对缓存池进行范围限制,在调度策略上,对某部分不太重要的消息进行丢弃处理
原有消息组件UI设计上存在一些问题:消息Cell采用的是子控件堆叠的设计,视图层级过多;简单使用系统原生控件,未对子控件的一些导致离屏渲染的操作进行处理(如圆角);一条消息一个消息样式一个自定义Cell,UITableView
缓存效率不高等。针对这些问题,我们可以进行一些改进:
- 减少视图层次,把多个视图预先渲染为一张图片
- 使用
NSAttributedString
处理图文混排的情况,这里可以配合一些富文本优化方案进行,也可借助一些第三方控件进行富文本处理,如YYLable
等 - 对不规则图像的优化处理,如圆角等场景可使用图片遮罩或绘制方式解决
- 优化消息Cell的设计,将多条样式合归整到一个Cell内,通过对子控件的Hidden处理,灵活对应业务样式
原有消息组件数据组装方式采用的是简单的Model -> View
映射方式,这样使用的问题在于,UITableView
重用的过程中会多次调用重用方法如tableView:cellForRowAtIndexPath:
及tableView:heightForRowAtIndexPath:
等,若在重用方法内进行些需CPU开销的业务处理,如Autolayout的高度计算、富文本的转换生成会加重CPU负担,进而导致界面卡顿。因而须对控件数据组装方式进行调整,避免过多的CPU开销:
- 数据组装上采用
Model -> Layout -> View
的映射方式,抽象Layout类对原始Model进行包装加工。Layout类包含原始Model数据、子控件的布局信息、Cell的高度、富文本信息以及其他一些布局展示上需要使用的信息。 - 前置Layout类的生成时机,在获取Model数据的时候创建并生成对应的Layout类,不要在
UITableView
重用方法内生成 - 自定义Cell的高度直接从Layout类中获取
通过以上优化方案对公聊消息组件进行优化后,线上并发消息下,公屏卡顿的情况有所缓解,公聊消息组件能满足一般直播应用的使用需求。