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类。

图像

目前网络上流行的图片格式基本都是压缩格式,而图片的显示大致可分为以下几部分:

  1. 图像的IO加载
  2. 图像的解压
  3. 图像的处理,如blend,crop等等
  4. 图像的渲染

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中其他巧妙的技巧,在此请读者海涵:).

时间: 2024-10-13 17:32:23

AsyncDisplayKit技术分析的相关文章

蓝牙协议分析(7)_BLE连接有关的技术分析

转自:http://www.wowotech.net/bluetooth/ble_connection.html#comments 1. 前言 了解蓝牙的人都知道,在经典蓝牙中,保持连接(Connection)是一个相当消耗资源(power和带宽)的过程.特别是当没有数据传输的时候,所消耗的资源完全被浪费了.因而,对很多蓝牙设备来说(特别是功耗敏感的设备),希望在无数可传的时候,能够断开连接.但是,由于跳频(hopping)以及物理通道(Physical Channel)划分的缘故,经典蓝牙连接

3DSMAX建模技术分析

在游戏美术中,模型的建立是很重要的,今天卡拉小编与大家分享的是3DSMAX建模技术分析1 旋转建模 用于具有中心对称的物体的造型比较简单,只需用工 具画出对称截面,加入(旋转)修改器就可以得到三维实体,有些还可以加入一些特殊变形,以增强表现的效果.2 Loft放样建模 这种建模的含义是将一个二维的交错物件转换为完整的三维物件的一个处理过程,也就是将一个二维的造型物件沿着第三轴向构建出复杂曲面的模型.也可以这样理解这个过程:将许多2D(shape)造型物件紧密且整齐地排列于一条路经(path)上,

蓝牙4.0技术分析1-广播者角色

第1章  BlueTooth Roles-Broadcaster 1.1    广播类型 广播可设置以下几种类型: 1)   Connectable Undirected Event Type(可连接无定向广播) 2)   Connectable Directed Event Type(可连接定向广播) 3)   Scannable Undirected Event Type(可扫描无定向广播) 4)   Non-connectable Undirected Event Type(不可连接无定向

PLSQL_R12 MOAC多组织底层技术实现技术分析(Oracle VPD)

  2014-05-30 BaoXinjian In Capgemini  一. 介绍 之前一直存在对Oracle R12 多组织访问的一些疑惑,所以查询了一些相关资料,并介绍实现R12 MOAC的Oracle VPD技术 Oracle VPD全称Virtual Private Database, Oracle的一种控制数据访问的其中安全策略之一 Oracle数据安全策略访问实现方法 Role-based security create role cust_role; grant select

Java三大主流开源工作流引擎技术分析

Java三大主流开源工作流引擎技术分析 首先,这个评论是我从网上,书中,搜索和整理出来的,也许有技术点上的错误点,也许理解没那么深入.但是我是秉着学习的态度加以评论,学习,希望对大家有用,进入正题! 三大主流工作流引擎:Shark,osworkflow,jbpm! Shark的靠山是Enhydra.Enhydra做过什么呢?多了!从j2ee应用服务器,到o/r mapping工具,到这个工作流引擎等等.为什么Shark的持久层采用DODS来实现?就是因为他们是一家人. Jbpm的靠山是jboss

负载均衡技术分析与测试报告

负载均衡技术分析与测试报告                 目录 负载均衡测试报告... 1 负载均衡技术概述:... 2 服务器负载均衡... 2 链路负载均衡... 3 Outbound链路负载均衡... 3 Inbound链路负载均衡... 4 常见负载均衡调度算法... 5 测试目的... 6 测试环境搭建... 7 1:原始网络环境... 7 2:测试网络环境... 7 测试设备介绍... 8 1:产品介绍... 8 2:产品操作界面... 8 出现问题... 9 最终解决方案...

技术分析之OGNL表达式概述

1. OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写 * 所谓对象图,即以任意一个对象为根,通过OGNL可以访问与这个对象关联的其它对象 * 通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能.它使用相同的表达式去存取对象的属性 2. Struts2框架使用OGNL作为默认的表达式语言 * OGNL是一种比EL强大很多倍的语言 * xwork提供 OGNL表达式 * ognl-3

转: HTTP Live Streaming直播(iOS直播)技术分析与实现

http://www.cnblogs.com/haibindev/archive/2013/01/30/2880764.html HTTP Live Streaming直播(iOS直播)技术分析与实现 不经意间发现,大半年没写博客了,自觉汗颜.实则2012后半年,家中的事一样接着一样发生,实在是没有时间.快过年了,总算忙里偷闲,把最近的一些技术成果,总结成了文章,与大家分享. 前些日子,也是项目需要,花了一些时间研究了HTTP Live Streaming(HLS)技术,并实现了一个HLS编码器

【转】HTTP Live Streaming直播(iOS直播)技术分析与实现

HTTP Live Streaming直播(iOS直播)技术分析与实现 不经意间发现,大半年没写博客了,自觉汗颜.实则2012后半年,家中的事一样接着一样发生,实在是没有时间.快过年了,总算忙里偷闲,把最近的一些技术成果,总结成了文章,与大家分享. 前些日子,也是项目需要,花了一些时间研究了HTTP Live Streaming(HLS)技术,并实现了一个HLS编码器HLSLiveEncoder,当然,C++写的.其功能是采集摄像头与麦克风,实时进行H.264视频编码和AAC音频编码,并按照HL