请介绍一下ASDK的原理

精辟总结

ASDK 认为,阻塞主线程的任务,主要分为(布局计算\渲染\对象操作)三大类。前两个可以异步操作,但 UIKit 和 CA 相关操作必需在主线程进行。传统的CALayer(属性改变/动画产生)是通过delegate来通知UIView的, ASDK创建了ASDisplayNode. ASDisplayNode持有UIView和CALayer对象, 当ASDisplayNode的属性(比如frame/transform)改变后,它并不会立刻同步到其持有的 view 或 layer 去,而是把被改变的属性保存到内部的一个中间变量,稍后在需要时,再通过(某个机制)一次性设置到内部的 view 或 layer。

传统的CA

当一个触摸事件到来时,RunLoop 被唤醒,切换到UITrackingMode, App 中的代码会执行一些调整视图的操作;这些操作最终都会被 CALayer 捕获,并通过 CATransaction 提交到一个中间状态去。因为Observer监听了 BeforeWaiting 和 Exit 事件,RunLoop 即将进入休眠(或者退出)时, Observer 会被回调通知, 把所有的中间状态合并提交到 GPU 去显示.

ASDK模拟

当有些操作要在主线程时,ASNode 会把任务用 ASAsyncTransaction(Group) 封装并提交到一个全局的容器CALayer。当 RunLoop 进入休眠前、CA 处理完事件后,Observer会被回调通知, ASDK 就会执行该 loop 内提交的所有任务。



ASDK 对于绘制过程的优化有三部分:分别是栅格化子视图、绘制图像以及绘制文字。
它拦截了视图加入层级时发出的通知 - willMoveToWindow: 方法,然后手动调用 - setNeedsDisplay,强制所有的 CALayer 执行 - display 更新内容;
然后将上面的操作全部抛入了后台的并发线程中,并在 Runloop 中注册回调,在每次 Runloop 结束时,对已经完成的事务进行 - commit,以图片的形式直接传回对应的 layer.content 中,完成对内容的更新。

image.png

在 ASDK 中的渲染围绕 ASDisplayNode 进行,其过程总共有四条主线:

  1. 初始化 ASDisplayNode 对应的 UIView 或者 CALayer;
  2. 在当前视图进入视图层级时执行 setNeedsDisplay;
  3. display 方法执行时,向后台线程派发绘制事务;
  4. 注册成为 RunLoop 观察者,在每个 RunLoop 结束时回调。

https://www.jianshu.com/p/276df9732a70

传统UIView就是CALayer的delegate

系统调用CALayer的display, 进行更新内容
display方法会调用layer的delegate的displayLayer方法, 进行更新内容
通常UIView就是CALayer的delegate


核心在于ASDisplayNode
ASDisplaynode可以实现异步执行:

  1. 层次计算
  2. 渲染布局

绘制的入口是ASDisplayLayer的displayAsyncLayer: asynchronously:
在这个方法里做了三件事情

  1. 递归获取displayBlock(绘图操作, 可以异步执行)
  2. 渲染完成后的completion block(必须在主线程中进行)
  3. 调度displayBlock

displayBlock 的构建

displayBlock 的创建一般分为三种不同的方式(不重要):

  1. 将当前视图的子视图压缩成一层绘制在当前页面上
  2. 使用 - displayWithParameters:isCancelled: 返回一个 UIImage,对图像节点 ASImageNode 进行绘制
  3. 使用 - drawRect:withParameters:isCancelled:isRasterizing: 在 CG 上下文中绘制文字节点 ASTextNode

这三种方式都通过 ASDK 来优化视图的渲染速度,这些操作最后都会扔到后台的并发线程中进行处理。


在何处注册了runloop
向mainRunloop注册Observer的地方有两个。

  1. 对应的处理是完成mainTransactionGroup的提交,上面我们在分析CALayer中获取_ASAsyncTransaction时,提到了CALayer会被添加至mainTransactionGroup中。这时候mainTransactionGroup在提交时会将自己管理的CALayer当前的_ASAsyncTransaction对象进行提交,从而完成layer的绘制工作。

  2. 向mainRunloop注册Observer的另一个处是在ASRunLoopQueue类初始化中。这里observer注册被调用的时机是在runloop开始sleep的时候。并创建了一个runLoopSource用来避免runLoop没有任务的时候会自动退出。同时在新任务到来的时候唤醒runLoop。
    回调processQueue函数主要从内置的_internalQueue中取出_batchSize个任务进行处理。处理任务调用的block是_queueConsumer,也就是上面初始化函数传过来的handlerBlock。那我们到ASRunLoopQueue被初始化的地方看到handlerBlock定义如下:
    大家可以看到ASRunLoopQueue就是典型的生产者-消费者模式。ASRunLoopQueue的实例renderQueue是一个单例对象,当ASDisplayNode节点需要被重新绘制的时候,则将该node添加至renderQueue中,然后在mainRunloop对象中被调度处理,处理结束后将该节点从Queue中移除。
    这里的任务主要来自于我们在修改Node的内容,需要重新绘制时,会调用ASDisplayNode的setNeedsDisplay方法(类似于UIView的setNeedsDisplay方法),这时候node会将自己添加到renderQueue中,等待被重绘。
    这里主要对node内置的layer进行递归重新绘制,其中在[layer displayIfNeeded]可能会重新调起CALayer的display方法,则会触发上面创建_ASAsyncTransaction,然后生成绘制displayBlock的流程。

iOS 保持界面流畅的技巧
https://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345