【转】iOS弹幕库OCBarrage-如何hold住每秒5000条巨量弹幕
最近公司做新需求, 原来用的老弹幕库, 已经无法满足需要. 迫不得已自己写了一套弹幕库OCBarrage. 这套弹幕库轻量, 可拓展, 高度自定义, 超高性能, 简单易上手.
无论哪家公司软件的性能绝对是衡量APP好坏的重要指标. 之前有一次开会, 我们领导说:”我们写的东西, 有哪些是可以拿的出手,让我们引以为豪的?”. 之前还真就得想一会儿, 现在可以毫不犹豫的说我们的弹幕库绝对是一个好家伙.
做直播类软件核心功能一个是播放器另一个就是弹幕了. 现在iOS开源的弹幕库性能好的不多, 弹幕量稍微大一点, 或者弹幕稍微复杂一点, 就会出现卡顿,这与它的底层实现, 设计策略以及你的使用方法都有关系. 关键是动画单一,无法定制,满足不了动画的多样化需求!OCBarrage正是为解决这些问题而生的!
OCBarrage底层使用Core Animation驱动, Core Graphics绘图, GPU渲染, 性能极高, 哪怕是同时渲染5000条弹幕也不会感觉到卡顿. 开源地址:https://github.com/w1531724247/OCBarrage
(以下测试基于iPhone7真机)
对于全民直播这样的平台来说,在大主播高峰时期的弹幕量是很大的,特别是当主播说一句:“我们现在开始弹幕抽奖”。弹幕量瞬间就会涨的很高!所以对弹幕这一块的要求还是蛮高的.
性能优化原理
弹幕渲染时比较耗性能的点:
1. ######弹幕阴影
主播在户外直播时偶尔会有白色的背景, 而弹幕文字的颜色也是白色的, 这个时候弹幕飘到直播画面的白色区域会导致看不到文字内容. 为了解决这个问题我们通常会给弹幕文字添加一个隐影.以防止这种情况的发生. 然而别小看这几个像素阴影, 它可是性能消耗的大户. 哪怕是用GPU渲染因为是动态的实时的所以也相当吃性能. 在实验的过程中发现如果有文字阴影几十条弹幕就会出现弹幕卡顿, 结果就是弹幕抖动一跳一跳的.
解决办法就是用NSAttributeString
的NSStrokeColorAttributeName
属性设置文字的轮廓颜色替换文字阴影.效果对比如下:
都能解决我们的问题, 但是性能差的可不是一丁半点.
2. ######用CALayer替代UIView展示
与UIView相比CALayer更轻量. 性能更好.系统提供的组件为了保证其通用性, 难免有些冗余.这就是我们优化的空间.
3. ######弹幕文字下面的渐变色背景
彩色弹幕下面的渐变色背景如果用CAGradientLayer实现也是比较耗性能的, 但是如果是用图片呈现的话效果就会好的多, 但是不够灵活, 没关系, 我们都一并解决了.
4. ######将内容合成一张图片展现
将所有的内容呈现在layer上并布局好位置以后将所有的内容合成一张图片展现在barrageCell的layer上, 并删除所有的子subview及sublayer, 以提高性能.
基础类
OCBarrageManager
提供了弹幕渲染视图并负责弹幕引擎的启动, 暂停, 继续及停止.
- renderView
:弹幕呈现的视图.
- renderStatus
:renderView的状态, 开始, 暂停, 结束.
- - (void)resgisterBarrageCellClass:(Class)barrageCellClass withBarrageIndentifier:(NSString *)barrageIndentifier;
:
注册cell类型, 在调用- (void)renderBarrageDescriptor:(OCBarrageDescriptor *)barrageDescriptor;
方法的时候会根据barrageDescriptor的barrageIndentifier
去自动去缓存池中取一个注册的与barrageDescriptor的barrageIndentifier
相同的cell.并将传入的barrageDescriptor赋值给cell的barrageDescriptor属性.
- - (void)start;
:允许接收并渲染弹幕
- - (void)puase;
:暂停弹幕动画. 如果弹幕正在运动则会暂停在当前位置, 并且不会渲染并丢弃新收到的弹幕.
- - (void)resume;
:继续弹幕动画, 并渲染新收到的弹幕.
- - (void)stop;
: 清空当前正在动画的弹幕, 并停止接收渲染新的弹幕.
OCBarrageDescriptor
OCBarrageDescriptor是负责传递弹幕数据的类, 通过barrageIndentifier
找到对应的OCBarrageCell
并将数据展示在OCBarrageCell
上.
- positionPriority
:属性决定了弹幕渲染之后在视图层次上所处的位置, 因为经常会有一些比较重要的弹幕不希望被普通弹幕覆盖, 这个时候可以将重要弹幕的positionPriority
设置的高一点, 这样重要弹幕就可以渲染在普通弹幕的上方而不会被普通弹幕覆盖.
- animationDuration
:动画时间, 这条弹幕从开始到结束的总时间.
- touchAction
:弹幕被点击时候执行的动作.
- bindingOriginY
:本条弹幕在渲染的时候将frame.origin.y固定在bindingOriginY
的位置.>=0
时生效. 可以固定弹幕Y坐标的位置.
OCBarrageCell
呈现弹幕数据的视图.
- idle
:是否是空闲状态, 如果正在运动则为NO, 如果正在缓存池中等待被复用则为YES.
- idleTime
:弹幕动画执行完毕后的时间点. 弹幕动画执行完毕后当前cell会被放进缓存池等待下次复用减少cell创建释放的性能开销. 如果超过5秒没有被复用则会被释放回收内存, 减少内存占用.
- barrageIndentifier
:标识符. 通过这个属性与OCBarrageDescriptor类绑定. 与OCBarrageDescriptor
的barrageIndentifier
对应.
- barrageDescriptor
:当前展示的OCBarrageDescriptor.
- barrageAnimation
:当前cell所执行的动画.
- trackIndex
当前cell所在的弹幕轨道的索引.
- - (instancetype)initWithBarrageIndentifier:(NSString *)barrageIndentifier;
:根据传入的barrageIndentifier创建一个实例.
- - (void)addBarrageAnimationWithDelegate:(id<CAAnimationDelegate>)animationDelegate;
: 子类可以通过重写这个方法为当前cell添加自定义的动画类型.animationDelegate
默认为OCBarrageRenderView
, 可以监听动画执行完毕的事件以便将cell放入缓存池等待下次复用.
- - (void)updateSubviewsData;
:在这个方法里给cell的各个子视图赋值. 也可以在- (void)setBarrageDescriptor:(OCBarrageDescriptor *)barrageDescriptor
方法里给子视图复制. 在这个方法调用以后可以计算一下子视图的的大小及位置.. 也可以在 - (void)layoutSubviews
设置子视图的大小及位置.
- - (void)clearContents;
设置数据前清空一下上次展示的遗留内容.
- - (void)sizeToFit;
:根据子视图的边界自适应大小.
- - (void)convertContentToImageWithSize:(CGSize)contentSize;
: 将当前cell上的子视图的内容绘制成一张图片, 并将生成的图片赋值给当前cell的layer的contents属性展现出来. 这个方法要在设置完数据和布局完子视图的位置之后调用. 这个方法会自动调用- (void)layoutSubviews
因此不可以在layoutSubviews
里调用这个方法不然后造成死循环. 图片生成之后这个方法会执行removeAllSubViewsAndSublayers
删除当前cell上所有的子视图以及子layer以优化展示性能.所以不希望被删除的视图或者layer请在这个方法调用之后添加, 在这个方法执行之后建议将子layer或者子view设置为nil以回收内存.
- (void)prepareForReuse;
: 在复用之前要进行的操作可以放在这个方法里执行, 在重写这个方法的时候记得调用一下[super prepareForReuse];
.
OCBarrageRenderView
- animatingCells
: 正在运动的弹幕cell的数组.
- idleCells
: 弹幕动画执行完毕后等待复用的弹幕cell的数组.
- renderPositionStyle
: 新出生的弹幕的位置OCBarrageRenderPositionRandomTracks
, 有弹幕轨道, 新出生的弹幕随机展示在其中一条轨道上, 并且尽量不覆盖在还没呈现完整的正在出来的弹幕上-默认类型.OCBarrageRenderPositionRandom
没有弹幕轨道, y坐标完全随机.OCBarrageRenderPositionIncrease
有弹幕轨道, y坐标循环递增.
- renderStatus
: 引擎状态正在OCBarrageRenderStoped
, 不接收不渲染新弹幕. OCBarrageRenderStarted
接受并渲染新弹幕.OCBarrageRenderPaused
暂停中, 不接收不渲染新弹幕, 已经渲染的弹幕停留在当前所处的位置.
- - (void)resgisterBarrageCellClass:(Class)barrageCellClass withBarrageIndentifier:(NSString *)barrageIndentifier;
: 同OCBarrageManager
的- (void)resgisterBarrageCellClass:(Class)barrageCellClass withBarrageIndentifier:(NSString *)barrageIndentifier;
.
- - (nullable OCBarrageCell *)cellWithBarrageIndentifier:(NSString *)barrageIndentifier;
: 根据传入的barrageIndentifier从缓存池或者注册的cell列表中返回一个cell.
- - (void)fireBarrageCell:(OCBarrageCell *)barrageCell;
: 发射弹幕.
- - (void)start;
: 同OCBarrageManager
.
- - (void)puase;
: 同OCBarrageManager
.
- - (void)resume;
: 同OCBarrageManager
.
- - (void)stop;
: 同OCBarrageManager
.
OCBarrageTrackInfo
弹幕轨道信息类.
- trackIndex
: 弹幕轨道所在的位置.
- trackIdentifier
: 弹幕轨道标识符, 不同类型的弹幕, 不重用同一条轨道.
- nextAvailableTime
:下次可用时间, 主要是用来防止某条轨道上刚出现了一条弹幕还没有完全展现在屏幕上, 后面这条轨道上就又来了一条弹幕盖在之前的那个弹幕上, 影响用户体验.
- barrageCount
: 当前轨道的弹幕数量.
当然写到这里依然还有优化的空间, 后续会继续优化, 欢迎各位仁人志士共同探讨指点.
开源地址:https://github.com/w1531724247/OCBarrage
from:https://blog.csdn.net/w1531724247/article/details/77619111
【转】iOS弹幕库OCBarrage-如何hold住每秒5000条巨量弹幕的更多相关文章
- 鸿蒙开源第三方组件 ——B站开源弹幕库引擎的迁移(上)
鸿蒙入门指南,小白速来!0基础学习路线分享,高效学习方法,重点答疑解惑--->[课程入口] 目录: 一.弹幕库的基础知识 二.弹幕库的使用方法 三.sample解析 四.作者系列文章合集 前言 ...
- iOS 第三方库、插件、知名博客总结
iOS 第三方库.插件.知名博客总结 用到的组件 1.通过CocoaPods安装 项目名称 项目信息 AFNetworking 网络请求组件 FMDB 本地数据库组件 SDWebImage 多个缩略图 ...
- 一个线上运营着3000+人的游戏,因为我不小心一个DROP DATABASE,全没了。 怎么办??跟我HOLD住!!!
前言 今天下午3点,我按照惯例,打开游戏服务器,开新服部署嘛,游戏在腾讯开放平台,简单.闭着眼睛都OK.于是一轮子的复制黏贴拷贝,把服务器加起来,然后启动查看日志. ....突然发现不断的有Excep ...
- iOS - 静态库的创建与使用
在日常项目开发中,不论是为了两个公司项目上的业务交流还是为了减少项目的编译时间,有的时候我们会把项目中的私密内容打包成静态库,或者是把项目中变动较少一部分打包成静态库以便提高编译效率,那么下面我们就来 ...
- IOS静态库
如何在Xcode中创建C++静态库 http://jingyan.baidu.com/article/03b2f78c111fca5ea237ae26.html iOS 如何创建和使用静态库 http ...
- 快快快!27个提升效率的iOS开源库推荐
文章来源:http://www.csdn.net/article/2015-07-21/2825264-27-ios-open-source-libraries/1 我热爱开源,更喜爱那些花费宝贵的业 ...
- 封装ios静态库碰到的一些问题(一)
封装IOS动态库,碰到的第一个问题,就是资源文件的问题,如果将你的程序封装成为静态库,那么静态库中不会包含资源文件和xib文件,这个时候就需要自己封装bundle文件了,而笔者开发环境默认是xcode ...
- fir.im Weekly - 热门 iOS 第三方库大盘点
本期 fir.im Weekly 收集的热度资源,大部分关于Android.iOS 开发工具.源码和脑洞大开的 UI 动画,希望给你带来更多的工作创意与灵感. 盘点国内程序员不常用的热门iOS第三方库 ...
- iOS静态库.a文件制作和导入使用
iOS静态库.a文件制作: 1.新建Cocoa Touch Static Library工程 新建工程 - 选择iOS-FrameWork&Libary,选择 Cocoa Touch Stat ...
随机推荐
- mysql无法远程连接
在mysql的mysql数据库下: select user,host from user;(查看,没有本机的访问权限) grant all privileges on *.* to root@&quo ...
- 10个JavaScript常见BUG及修复方法
译者按: JavaScript语言设计太灵活,用起来不免要多加小心掉进坑里面. 原文: Top 10 bugs and their bug fixing 译者: Fundebug 为了保证可读性,本文 ...
- 数据分析 - 美国金融科技公司Prosper的风险评分分析
数据分析 - 美国金融科技公司Prosper的风险评分分析 今年Reinhard Hsu觉得最有意思的事情,是参加了拍拍贷第二届魔镜杯互联网金融数据应用大赛.通过"富爸爸队",认识 ...
- SSL与TLS 区别 以及介绍
SSL:(Secure Socket Layer,安全套接字层),位于可靠的面向连接的网络层协议和应用层协议之间的一种协议层.SSL通过互相认证.使用数字签名确保完整性.使用加密确保私密性,以实现客户 ...
- DAY9(PYTHON)
li=[{'usename':'xiaowang'}, {'} ] board=['张三','李四','王大麻子'] while 1: usename = input('用户名:') if usena ...
- (网页)jQuery判断checkbox是否选中的方法
if($('#checkbox-id').is(':checked')) { // do something} if ($('#checkbox-id').attr('checked')) { ...
- 上了IPD和CMMI,为什么还要搞敏捷?
文/资深顾问 杨学明 现在国内许多产品创新型企业一旦研发团队上了规模,就会进行IPD体系的变革或CMMI的认证,但现在还有一种更加流程的开发模式,就是敏捷,华为公司早在2009年正式发文在全公司现在流 ...
- oracle11在docker环境下的运行
目的 Ø 在测试的环境下oracle数据库不存在或访问不方便时,可以将这个环境快速恢复出来 Ø 开发时方便测试之用 可以在任何包含docker服务的机器上运行,具体的docker的安装可以参考如下: ...
- Python 常用的正则表达式
校验数字的相关表达式: 功能 表达式 数字 ^[0-9]*$ n位的数字 ^\d{n}$ 至少n位的数字 ^\d{n,}$ m-n位的数字 ^\d{m,n}$ 零和非零开头的数字 ^(0|[1-9][ ...
- [20190322]测试相同语句遇到导致cursor pin S的疑问.txt
[20190322]测试相同语句遇到导致cursor pin S的疑问.txt--//昨天测试遇到的情况,链接:http://blog.itpub.net/267265/viewspace-26388 ...