AsyncDisplayKit技术分析
转载请注明出处:http://xujim.github.io/ios/2014/12/07/AsyncDisplayKit_inside.html ,谢谢
前言
Facebook前段时间发布了其iOS UI框架AsyncDisplayKit(ASDK)的1.0正式版,这个框架被用于Facebook自家的应用Paper,能够提高UI的流畅性并缩短响应时间。AsyncDisplayKit附带了guide文档,有兴趣的同学可以参考这里。
然而本文主要着重于讨论AsyncDisplayKit的技术原理与其相对于于UIKit响应优化的技巧。
众所周知,在现行的UI framework如UIKit,Windows的DotNet一旦涉及到绘制,总是建议在UI thread中进行,并且许多API也总是依赖于UI线程,否则容易导致crash。这和各framework开发者想使自己的Framework易于使用,不易出错,更好维护的初衷有关。 但其实UI的展现涉及的几个主要步骤和UI线程并非一定要绑定在一起的。AsyncDisplayKit并没有使用特别高深的绘制或者如GPU优化等优化技巧,而是在UI展现过程中将几个重要阶段剥离主线程从而将UI的流畅性提高到极致。这几个重要阶段分别是布局、绘制、图像。下文将按这几个阶段阐述AsyncDisplayKit的技术技巧。
布局
UI框架中要布局一个UIView一般需要改写layoutSubviews或者layoutSublayers等函数,并且一旦修改了frame等属性必然会触发这类layout函数。而这些函数的实现往往自上而下,要根据container来measure子view的大小并且层层递归计算下去。如果UIView是个复杂的容器如UITableView等,则如此递归计算将很耗时间。 这个计算方法不可避免,但UIkit和其他传统的UI库都将这些工作放入主线程。那么一旦layoutSubview的计算成本过大,必然会导致UI的响应缓慢或者刷新有delay。
那就放入工作线程呗,但遇到绘制的线程同步问题,又让许多人望而却步。不过AsyncDisplayKit做到了。
以AsyncDisplayKit的ASTableView为例,TableView的UI布局需要计算每行的高度,然后计算行内元素的布局,将行插入到TableView中,同时TableView又是scrollview,需要上下滑动。一旦行的生成和渲染比较慢,必然影响到滑动时的流畅体验。在这个过程中只有将行插入到TableView中需要在UI线程中执行。
AsyncDisplayKit在子线程中分批次计算行(row)以及其子元素的布局,计算好后通过dispatch_group_notify通知UI线程将row插入到view中。 AsyncDisplayKit有一个比较细腻的方式是考虑到设备的CPU核数,根据核数来分批次计算row的大小。
每当row被sized之后,TableView便会触发row UI实体cell的生成,随之便是row中内容的绘制——这在后面会详述其中的高效技巧。
此处的技巧具体可参见sizeNextBlock函数。
绘制
AsyncDisplayKit另一个强大之处在于将UI CALayer的backing image的绘制放入到工作线程。
我们知道UIView的真正展现内容在于其CALayer的contents属性,而contents属性对应一个Backing image,我们可以将其理解成一个内存位图。默认情况下UIView一旦需要展现,其会自动创建一个Backing image,但我们也可以通过CALayer的delegate方式来定制这个Backing image。
AsyncDisplayKit就是通过CALayer的delegate控制backing image的生成,并且通过Core Graphic的方式在工作线程上将View以及其子节点绘制到backing image上,这些绘制工作会根据UIView的层次构建一个绘制数组统一执行,绘制好之后在UI线程上将这个backing image传给CALayer的contents,最后将CALayer的渲染树交给GPU进行渲染。虽然这个过程中主要依赖于CoreGraphic来进行绘制,但因为都在后台,而且绘制以组的方式执行减少了graphic context的切换,对于UI性能和顺滑性没有什么影响。
那backing image绘制好之后也是通过dispatch_group的方式通知UI线程吗?如果绘制节点很多通过这个API必然会导致错乱。AsyncDisplayKit在这里又将iOS的异步用到极致——他通过transaction的方式管理dispatch_group之间的关系,并且只有在UI线程处于idle状态或将退出时才将transaction commit并将backing image赋给CALayer的contents。
除了通过CAlayer的backing image绘制,AsyncDisplayKit还提供UIView的drawRect绘制以及UIView的rasterize。两者都会使用offscreen drawing,但后者会将UIView以及所有子节点都绘制在一个backing image上
此处所使用的技巧可参见_ASAsyncTransaction类。
图像
目前网络上流行的图片格式基本都是压缩格式,而图片的显示大致可分为以下几部分:
- 图像的IO加载
- 图像的解压
- 图像的处理,如blend,crop等等
- 图像的渲染
AsyncDisplayKit在此主要优化第二和第三阶段,毕竟IO加载往往通过异步IO或者预加载的方式进行优化,图像的渲染一般都是GPU进行快速渲染。
首先说图像的解压。或许你会问,我们通常IO加载图像后就生成UIImage了,尽管我们知道图像肯定要解压,但似乎没有API供我们调用啊?这就是AsyncDisplayKit的高明之处。
一般UIImage对其内部图像格式的解压发生在即将将图片交给GPU渲染的时候。从API上来看,一般我们调用[UIImage drawInRect]函数或者将UIView可见(放置于window上)的时候,UIImage会将其内部图像格式如PNG,JPEG进行解压。AsyncDisplayKit就是采用后面那个方式将UIView预先放置入一个frame为空得workingview中以达到将view内部的image进行预解压的目的。
此处还是以ASTableView为例。当前table view中可见的rows中得图片肯定是会发生解压的,但table view需要经常滑动rows操作,那么可见的rows上下需要增加一些缓存区来预处理即将展示的rows,如此在互动窗口上移或下移的时候,这些缓存的rows能快速渲染并马上展示到UI上。AsyncDisplayKit通过working range来管理这上下缓存,通过将working rows放置入frame为(0,0,0,0)的UIWindow中进行row内部image的预解压和预生成。
再说图像的处理。一般图像需要一些blend运算或者图像需要strech或crop,这些工作其实可以留在GPU中进行快速计算,但因为UIKit并没有提供此类的API,所以我们一般都是通过CoreGraphic来做,但CoreGraphic是CPU drawing比较费时。AsyncDisplayKit将这些图像处理放在工作线程中来处理,虽然也是CPU drawing,但不会影响到UI得顺滑响应。具体此处的技术实现可以看ASImageNode的代码。
结尾
综上,AsyncDisplayKit如庖丁解牛一般熟悉UI绘制整个过程中得经络,将一些可以移到工作线程的工作剥离主线程,并且高超的使用iOS中得线程技巧做好同步,达到了提供UI流畅顺滑的效果,让人心中一亮,为之侧目!
更重要的是:这些技术技巧其实是通用的,完全可以用于iOS甚至Android等其他客户端的编程当中。
当然,AsyncDisplayKit大量的采用线程,也带来了一些接口API在线程同步中不好使用的问题,为了避免或者解决这些问题,需要你对其原理有理解。同时AsyncDisplayKit在text绘制上采用TextKit方式,所以对老版本的iOS不兼容。
此外,本文目的在于介绍AsyncDisplayKit的一些通用技巧,所以文中没有插入特殊的Objective c代码片段。而且因为时间关系,或许漏掉了AsyncDisplayKit中其他巧妙的技巧,在此请读者海涵:).
AsyncDisplayKit技术分析的更多相关文章
- 蓝牙协议分析(7)_BLE连接有关的技术分析
转自:http://www.wowotech.net/bluetooth/ble_connection.html#comments 1. 前言 了解蓝牙的人都知道,在经典蓝牙中,保持连接(Connec ...
- WaterfallTree(瀑布树) 详细技术分析系列
前言 WaterfallTree(瀑布树) 是最强纯C#开源NoSQL和虚拟文件系统-STSdb专有的(版权所有/专利)算法/存储结构. 参考 关于STSdb,我之前写过几篇文章,譬如: STSdb, ...
- iOS直播的技术分析与实现
HTTP Live Streaming直播(iOS直播)技术分析与实现 发布于:2014-05-28 13:30阅读数:12004 HTTP Live Streaming直播(iOS直播)技术分析与实 ...
- 横向技术分析C#、C++和Java优劣
转自横向技术分析C#.C++和Java优劣 C#诞生之日起,关于C#与Java之间的论战便此起彼伏,至今不辍.抛却Microsoft与Sun之间的恩怨与口角,客观地从技术上讲,C#与Java都是对传统 ...
- tolua++实现lua层调用c++技术分析
tolua++技术分析 cocos2dx+lua 前言 一直都使用 cocos2dx + lua 进行游戏开发,用 Lua 开发可以专注于游戏逻辑的实现,另外一方面可以实现热更新:而且 lua 是一个 ...
- 美链BEC合约漏洞技术分析
这两天币圈链圈被美链BEC智能合约的漏洞导致代币价值几乎归零的事件刷遍朋友圈.这篇文章就来分析下BEC智能合约的漏洞 漏洞攻击交易 我们先来还原下攻击交易,这个交易可以在这个链接查询到. 我截图给大家 ...
- NetSarang软件中nssock2.dll模块被植入恶意代码技术分析与防护方案
原文地址:http://blog.nsfocus.net/nssock2-dll-module-malicious-code-analysis-report/ NetSarang是一家提供安全连接解决 ...
- 包建强的培训课程(3):App竞品技术分析
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- 【渗透技术】渗透测试技术分析_TomCat
[渗透技术]渗透测试技术分析_TomCat 本文转自:i春秋论坛 渗透测试-中间人攻击(原理)说起“中间人攻击”我想大多数对渗透测试又了解的朋友都多少有所了解,因为我们用到的次数真是非常的多.它可以将 ...
随机推荐
- 获取url传的参数转变为对象的方法
function GetRequest() { var url = location.search; //获取url中"?"符后的字串 var theRequest = new O ...
- 性能测试工具LoadRunner20-LR之Controller Service-Level Agreement(服务水平协议)
SLA是为负载测试场景定义的具体目标.例如,评测脚本中任意数量事务的平均响应时间,可以定义具体的目标或阈值.测试运行结束之后,LR将你定义的目标与实际录制的平均事务响应时间进行比较.如果实际的平均事务 ...
- 在mac上使用github for mac 创建并上传项目
1.下载github for mac https://mac.github.com/ 2.登陆 偏好设置 3.用Xcode 创建一个项目,勾上“create local git respository ...
- Eclipse Infrastructure
Everything is plug-ins running on or loaded by plug-ins loader called by a small kernal which is an ...
- Android无需权限显示悬浮窗
TYPE_TOAST一直都可以显示, 但是用TYPE_TOAST显示出来的在2.3上无法接收点击事件, 因此还是无法随意使用. 下面是我之前研究后台线程显示对话框的时候记得笔记, 大家可以看看我们项目 ...
- u-boot分析(五)----I/D cache失效|关闭MMU和cache|关闭看门狗
u-boot分析(五) 上篇博文我们按照210的启动流程,对u-boot启动中的设置异常向量表,设置SVC模式进行了分析,今天我们继续按照u-boot的启动流程对以下内容进行分析. 今天我们会用到的文 ...
- 夜色的 cocos2d-x 开发笔记 02
本章我们让飞机发射子弹,因此我们要写这样一个方法 子弹资源:欢迎下载 很详细的注释吧,现在有几个地方报错,.h文件里面一定要先声明 这里是本章所有的新方法,你可以一次声明全部,嗯,还有个报错应该是我们 ...
- Arcgis for Js之鼠标经过显示对象名的实现
在浏览地图时,移动鼠标经过某个对象或者POI的时候,能够提示该对象的名称对用户来说是很实用的,本文讲述在Arcgis for Js中,用两种不同的方式来实现该效果. 为了有个直观的概念,先给大家看看实 ...
- DB2安装教程图解
下载好之后,是exe文件,但是双击后基本上都是解压,但是使用自身的解压的话会有很多文件解压失败的情况,所以推荐使用自己电脑上自带的解压工具直接解压(如360解压,好压等). 解压之后直接运行setup ...
- 还是要精简开发呀,VS2015太大,VS2010不想装
公司电脑配置没有很好,所以对于我就是一个挑战. vs2015装上了,但是一打开就卡卡卡,基本没法办公. 公布能用记事本吧,太多不方便: Notepad++做辅助的局部修改还是很好用的,装上插件就智能提 ...