美文网首页Swift收藏iosiOS开发常用
iOS弹幕库OCBarrage-如何hold住每秒5000条巨量

iOS弹幕库OCBarrage-如何hold住每秒5000条巨量

作者: 股金杂谈 | 来源:发表于2017-08-26 16:11 被阅读3728次

    最近公司做新需求, 原来用的老弹幕库, 已经无法满足需要. 迫不得已自己写了一套弹幕库OCBarrage. 这套弹幕库轻量, 可拓展, 高度自定义, 超高性能, 简单易上手.
    无论哪家公司软件的性能绝对是衡量APP好坏的重要指标. 之前有一次开会, 我们领导说:"我们写的东西, 有哪些是可以拿的出手,让我们引以为豪的?". 之前还真就得想一会儿, 现在可以毫不犹豫的说我们的弹幕库绝对是一个好家伙.
    做直播类软件核心功能一个是播放器另一个就是弹幕了. 现在iOS开源的弹幕库中性能好的不多, 弹幕量稍微大一点, 或者弹幕稍微复杂一点, 就会出现卡顿,这与它们的底层实现, 设计策略以及你的使用方法都有关系. 关键是动画单一,无法定制,满足不了动画的多样化需求!OCBarrage正是为解决这些问题而生的!
    OCBarrage底层使用Core Animation驱动, Core Graphics绘图, GPU渲染, 性能极高, 哪怕是同时渲染5000条弹幕也不会感觉到卡顿. 开源地址:https://github.com/w1531724247/OCBarrage
    (以下测试基于iPhone7真机)

    同时渲染2000条弹幕.gif 同时渲染3000条弹幕.gif 同时渲染4000条弹幕.gif 同时渲染5000条弹幕.gif

    对于全民直播这样的平台来说,在大主播高峰时期的弹幕量是很大的,特别是当主播说一句:“我们现在开始弹幕抽奖”。弹幕量瞬间就会涨的很高!所以对弹幕这一块的要求还是蛮高的.

    性能优化原理

    弹幕渲染时比较耗性能的点:

    1. 弹幕阴影

    主播在户外直播时偶尔会有白色的背景, 而弹幕文字的颜色也是白色的, 这个时候弹幕飘到直播画面的白色区域会导致看不到文字内容. 为了解决这个问题我们通常会给弹幕文字添加一个隐影.以防止这种情况的发生. 然而别小看这几个像素阴影, 它可是性能消耗的大户. 哪怕是用GPU渲染因为是动态的实时的所以也相当吃性能. 在实验的过程中发现如果有文字阴影几十条弹幕就会出现弹幕卡顿, 结果就是弹幕抖动一跳一跳的.
    解决办法就是用NSAttributeStringNSStrokeColorAttributeName属性设置文字的轮廓颜色替换文字阴影.效果对比如下:

    text_shadow.png text_stroke.png

    都能解决我们的问题, 但是性能差的可不是一丁半点.

    1. 用CALayer替代UIView展示

    与UIView相比CALayer更轻量. 性能更好.系统提供的组件为了保证其通用性, 难免有些冗余.这就是我们优化的空间.

    1. 弹幕文字下面的渐变色背景

    彩色弹幕下面的渐变色背景如果用CAGradientLayer实现也是比较耗性能的, 但是如果是用图片呈现的话效果就会好的多, 但是不够灵活, 没关系, 我们都一并解决了.

    1. 将内容合成一张图片展现

    将所有的内容呈现在layer上并布局好位置以后将所有的内容合成一张图片展现在barrageCell的layer上, 并删除所有的子subview及sublayer, 以提高性能.

    效果演示

    demonstration.gif walkBarrage.gif mixedImageAndText.gif stopover.gif

    使用用法

    • 第一步:

    为新的弹幕类型新建一个数据模型 例如:OCBarrageWalkBannerDescriptor. 这个类必须继承自OCBarrageDescriptor类.

    OCBarrageWalkBannerDescriptor.png
    这样就创建新的弹幕类型的数据模型类, 我们可以在这个类里面添加新的弹幕属性例如:bannerLeftImageSrc, bannerMiddleColor, bannerRightImageSrc等等.
    • 第二步:

    为新的弹幕类型创建建一个数据展示视图例如:OCBarrageWalkBannerCell. 这个新的弹幕类型的展示视图必须继承自OCBarrageTextCell类.

    OCBarrageWalkBannerCell.png

    在这个新的展示视图里我们可以添加展示相应数据的子视图,例如:leftImageView, middleImageView, rightImageView.
    并为这个新的视图类添加一个相应的数据模型类的属性OCBarrageWalkBannerDescriptor *walkBannerDescriptor来传递数据.

    • 第三步:
      重写新视图OCBarrageWalkBannerCell- (void)setBarrageDescriptor:(OCBarrageDescriptor *)barrageDescriptor方法. 并只能在这个方法里为walkBannerDescriptor属性赋值, 在这个方法里必须要调用[super setBarrageDescriptor:barrageDescriptor]方法, 不然barrageDescriptor属性将没有值, 并且部分属性设置将不生效.OCBarrageCell本身有一个barrageDescriptor属性引用数据模型. 但是为了方便拓展我们选择在第二步里为OCBarrageWalkBannerCell添加一个新的数据属性walkBannerDescriptor. 实质上OCBarrageWalkBannerCellbarrageDescriptor属性和walkBannerDescriptor指向的是同一个walkBannerDescriptor对象.
    setBarrageDescriptor.png
    • 第四步:

    重写新视图OCBarrageWalkBannerCell- (void)updateSubviewsData方法. 渲染引擎在渲染弹幕视图之前会自动调用这个方法. 我们可以在这个方法里为子视图设置数据

    updateSubviewsData.png

    .

    • 第五步:

    在第四步设置好子视图的数据之后就可以计算并设置子视图的大小和位置.重写- (void)layoutContentSubviews方法, 并在这个方法里布局子视图的位置.渲染引擎会在调用- (void)updateSubviewsData方法之后自动调用- (void)layoutContentSubviews方法, 这个方法必须在主线程执行.

    layoutContentSubviews.png
    • 第六步:

    在布局好子视图的位置之后, 如果想要提高性能可以调用- (void)convertContentToImage方法, 将可以图像化的视图合成一张图片展示在cell的layer上, 渲染引擎会在调用- (void)layoutContentViews方法之后自动调用- (void)convertContentToImage方法, 这个方法必须在主线程执行.

    convertContentToImage.png

    如果不想将子视图的内容转化成图片只需重写- (void)convertContentToImage并留空即可:

    convertContentToImage.png
    • 第七步:

    如果想要进一步优化内存和性能, 可以重写- (void)removeSubViewsAndSublayers方法, 删除之前添加的的subView和sublayer, 并将子视图置为nil.

    removeSubViewsAndSublayers.png

    如果既想提高性能, 又有一些无法图片化的内容(例如:gif)需要展示, 可以重写- (void)removeSubViewsAndSublayers方法但不调用[super removeSubViewsAndSublayers]方法, 并选择性的删除一些子视图, 保留一些子视图.

    如果不想删除子视图, 只需重写- (void)removeSubViewsAndSublayers方法并留空即可:

    removeSubViewsAndSublayers.png

    当然写到这里依然还有优化的空间, 后续会继续优化, 欢迎各位仁人志士共同探讨指点.
    开源地址:https://github.com/w1531724247/OCBarrage

    补充说明:
    cell会在动画执行完之后调用- (void)prepareForReuse, 在数据设置并布局完准备展示的时候调用- (void)removeSubViewsAndSublayers, 如果在- (void)removeSubViewsAndSublayers里将子视图删除了, 下次重用的时候要在- (void)prepareForReuse里重新加一下子视图

    想知道实际效果如何吗?赶快扫码下载体验吧!


    图片.png

    相关文章

      网友评论

      • 淘代码者:重叠的问题 有办法解决没
        股金杂谈:@淘代码者 有优化的建议可以告诉我,我优化下
        淘代码者:cpu 耗得有点高
        股金杂谈:@淘代码者 有的。 想办法把他们的总运行距离和运行时间设置相同就可以了。 就是让他们的速度相同。 他们就不会重叠了
      • 7f4b0d14ea8d:问一下 如果在点击每一条弹幕触发一个事件 要怎么做啊
        股金杂谈:@rangguangyu 这个功能已经实现了。但是没有同步到github上。 说嘛。三言两语也说不清。 你自己看看源代码。 可以在那个上面改
      • timelove:我这边就是普通视频显示弹幕,服务器把一堆弹幕数据给我们,我们根据弹幕发送时间去显示类似你们直播回放,我目前打算根据播放器时间回调没次回调检查当前时间点需要插入弹幕不,重播清空再反复这样操作,我觉得不太好。目前这个库也没提供弹幕根据时间渲染显示,所以想请教一下,有没有什么好的建议,你们是如何处理这种场景的?请大佬指教一下,谢谢!!!
        股金杂谈:@timelove 暂时不会做根据时间播放的功能!限制弹幕在顶部和底部的功能已经有了,barrageDescriptor有个randerRange属性,可以控制渲染位置
        timelove:@填坑侠 谢谢回复,那你们后续会更新这样的功能吗? 另外我想限制弹幕行数(或限制弹幕显示在顶部底部)这样的操作有吗,我没找到这样的API接口:smile:
        股金杂谈:@timelove 先根据播放器回调做吧!现在没提供根据时间渲染的功能
      • Kailan2020:所有的事件都会被 OCBarrageRenderView 拦截掉而到不了我自己的业务 view,这时候你如果在自己的业务 View 上添加一个 Button,而 OCBarrageRenderView 又在 Button 之上的话,那么点击这个 Button 是无效的。这种情况下 有什么方法解决,点击某条弹幕可以响应,当没有弹幕的时候点击这个button,button响应。 我把button添加到OCBarrageRenderView上,弹幕是直接飘在button底下的。 有没有办法让弹幕飘在最上层。
        Kailan2020:@填坑侠 好的。谢谢。
        股金杂谈:@凯子哟 有啊。 把button添加到OCBarrageRenderView上的时候,不要用addSubview加,用insertSubview:atIndex:加, index传0就好了:smile:
      • ghkggjj:demo 有内存泄漏
        1. 点我 进入弹幕页
        2. 点击开始
        3. 点击停止
        4. delloc 未触发
        股金杂谈:@ghkggjj :+1: 我再检查检查, 如果你改好了。也可以提上去, 大家共同维护嘛!:smile:
      • ghkggjj:东西很赞,github 上竟然没有star? ???
        ghkggjj:@填坑侠 写的非常不错,只是小问题 😄
        股金杂谈:@ghkggjj https://github.com/iOS-Strikers/OCBarrage 这个链接star数多点
      • 嘴爷:兄弟可以,我先赞了~
      • xx_cc:你好,请问一下,可以设置弹幕移动的方向吗,例如从下至上?
        xx_cc:好的,非常感谢。
        股金杂谈:可以啊!只需要在addBarrageAnimationWithDelegate:里改一下startCenter和endCenter的值即可!我刚更新了demo, 里面加了从上往下的动画你可以下载运行看一下
      • 35e9b54d38d2:怎么避免重叠?
        35e9b54d38d2:@填坑侠 要把removeSubViewsAndSublayers也删掉才行。这种方式效率挺高的,但我为什么不用这个呢,因为生成的图片估计尺寸不对,有压缩现象,谢谢楼主
        35e9b54d38d2:@填坑侠 convertContentToImage内容清空后,就不显示了
        股金杂谈:@sj_2bac 暂时没这个功能
      • 月醉花听:怎么把弹幕清空
        股金杂谈:@月醉花听 :+1:
        月醉花听:@填坑侠 谢了 老哥 有什么问题我再问你
        股金杂谈:调用一下stop方法就可以清空了:blush:
      • Callmewenxi:进入后台再切换回前台,弹幕会被系统清掉,这个问题有办法解决吗?
        股金杂谈:@iOS小小白 你说的这个"进入后台再切换回前台,弹幕会被系统清掉"的问题已经解决了, 用最新版就可以了
        Callmewenxi:@填坑侠 CALayer动画,如果切到其他界面或者是退到后台,会被系统自动移除掉的,貌似无解:sweat:
        股金杂谈:@iOS小小白 我看看,修复之后告诉你:blush:
      • aaasun:你好,请问一下,这个里面设置图片是怎么设置的呢?直接通过NSTextAttachment添加进去,但是没有显示呢
        股金杂谈:@aaasun 这个也比较简单用YYLabel设置好图文混排的内容之后,再加到cell上!
        aaasun:@填坑侠 就是文本前面或者中间有图片的情况
        股金杂谈:你是说图文混排, 还是添加图片?

      本文标题:iOS弹幕库OCBarrage-如何hold住每秒5000条巨量

      本文链接:https://www.haomeiwen.com/subject/ihjmdxtx.html