Node Containers
ASCollectionNode : UICollectionView
ASPagerNode : UIPageViewController
ASTableNode : UITableView
ASViewController : UIViewController
ASNavigationController
ASTabBarController
Node Subclasses
ASDisplayNode : UIView
ASCellNode : UITableViewCell
ASScrollNode : UIScrollView
ASEditableTextNode : UITextView
ASControlNode : UIControl
ASButtonNode : UIButton
ASTextNode : UILabel
ASImageNode : UIImageView
ASNetworkImageNode
ASMultiplexImageNode
ASNetworkImageNode : // 此类用于家中网络图片
ASVideoNode AVPlayerLayer
ASVodeoPlayerNote UIMoviePlayer
Subclassing
ASDisplayNode
init (background thread)
didLoad (main thread) viewDidLoad touch事件,手势在这里执行
layoutSpecThatFits (background thread)计算布局的主要方法
layout (main thread) viewWillLayoutSubviews
ASViewController
init initWithNode
loadView set it node.view for you
viewDidLoad requires to the viewe/layer , adding gesture recognizer
viewWillLayoutSubviews 与node的layout方法一起调用 (写布局逻辑)
viewWillAppear 统计用户行为Log
viewDidDisappear
layoutSpecTahtFits
Layout Specs
ASWrapperLayoutSpec:
wrap layoutElement and calculated the layout of the child based on the size set on the layout element
ASStackLayoutSpec :
direction :(决定主轴方向)
spacing,
horizontalAlignment :
verticalAlignment :
justifyContent :(项目在主轴方向的对齐方式),
alignItems :(项目在交叉轴上的对齐方式)
alignContent :(多根轴线的对齐方式)
flexWrap :(单行or多行)
ASInsetLayoutSpec:
一旦子节点确定它的最终大小,插图规格将其最终大小按照其子节点的大小加上 其插入边距。由于插图布局规范的大小基于其子节点的大小,因此子节点必须具 有内在大小或明确设置其大小。
ASOverlayLayoutSpec
把它的子节点放在另一个组件上,作为叠加,覆盖规格的大小是根据子节点的大 小计算的,子节点必须具有固有的大小或设置的大小(子节点在下面)
ASBackgroundLayoutSpec
放置一个组件,将其后面的另一个组件作为背景展开。背景规格的大小根据子节 点的大小计算,重要的是子节点必须具有固有的大小或设置的大小(子节点在上面)
ASCenterLayoutSpec
ASCenterLayoutSpec其中心内最大的子节点constrainedSize, ASCenterLayoutSpec 有两个属性:centeringOptions:确定子节点在中心规格 中居中的方式。选项包括:None,X ,Y,XY。sizingOptions:确定中心规格 将占用多少空间。选项包括:Default,最小X,最小Y,最小XY。
ASRatioLayoutSpec
可以扩展的固定长宽比布置组件。该规范必须有一个宽度或高度传递给它作为约 束尺寸,因为它使用此值来缩放自身。
ASRelativeLayoutSpec
根据垂直和水平位置说明符,放置组件并将其放置在布局边界内。类似于“9部 分”图像区域,子节点可以位于四个角中的任何一个,也可以位于四个边中的任 何一个以及中心
ASAbsoluteLayoutSpec
通过子节点的layoutPosition属性来确定子节点的位置(x/y坐标中)
ASCornerLayoutSpec
解释这种情况的最佳方案是在用户的头像图像的角落添加一个小badge视图,并且无需担心超出badge(超出头像图像frame)可能会影响 整个布局大小。 默认情况下,仅当您手动打开wrapsCorner属性时,角元素的大小才会添加到布局大小。
Layout Element Properties
ASStackLayoutElement Properties
.style.spacingBefore :在堆叠方向上放置对象之前的额外空间
.style.spacingAfter :在堆叠方向上放置对象之后的额外空间
.style.flexGrow :是否放大多少倍
.style.flexShrink :是否缩小多少倍
.style.flexBasis :原始大小()
.style.alignSelf :重新在父类中item的布局方向,修改item对齐方式(AlignSelfAuto,Start,End,Center,Stretch)
.style.ascender :从顶部到基准线的距离
.style.descender :从底部到基准线的距离
ASAbsoluteLayoutElement Properties
.style.layoutPosition :在parent Spec 中自己的position
ASLayoutElement Properties
.style.width
.style.height
.style.minWidth
.style.maxWidth
.style.minHeight
.style.maxHeight
.style.preferredSize intrinsic content size (calculateSizeThatFits)
.style.minSize
.style.maxSize
.style.preferredLayoutSize RELATIVE
.style.minLayoutSize
.style.maxLayoutSize
ASDimension CGFloat .style.flexBasis
dimension returned is relative(%)
ASDimensionMake(@50%)
ASDimensionMakeWithFraction(0.5)
dimension returned in points
ASDimensionMake(@“70pt”)
ASDimensionMake(70);
ASDimensionMakeWithPoints(70);
Sizes(CGSize,ASLayoutSize) .style.preferredLayoutSize, .style.minLayoutSize, .style.maxLayoutSize
CGSize .style.preferredSize .style.minSize .style.maxSize
ASSizeRange (minimum and maximum CGSize pair)
layoutSpecThatFits:
Flex Box 弹性布局
main axis; main start; main end; main size;
cross axis; cross start; cross end; cross size
6个容器的属性
flex-direction
row(默认值) : 主轴为水平方向,起点在左端.
row-reverse : 主轴为水平方向,起点在右端.
column : 主轴为垂直方向,起点在上沿.
column-reverse : 主轴为垂直方向,起点在下沿
flex-wrap
nowrap(默认) :不换行.
wrap :换行,第一行在上方
wrap-reverse :换行,第一行在下方
flex-flow
flex-direction || flex-wrap
justify-content
在主轴上的对齐方式
flex-start (默认值) : 左对齐
flex-end : 右对齐
center : 居中
space-between : 两端对齐,item之间间隔相等
space-around : item两侧的间隔相等,item与边框的间隔小
align-items
在交叉轴上对齐方式
flex-start : 交叉轴起点对齐
flex-end : 交叉轴终点对齐
center : 交叉轴中点对齐
stretch(默认值) : 如果item未涉足高度或者设为auto,将占满整个容器的高度
baseline : item第一行文字的基线对齐
align-content
属性定义多根轴线的对齐方式(只有一根轴线时不起作用)
flex-start : 与交叉轴的起点对齐
flex-end : 与交叉轴的终点对齐
center : 与交叉轴的中点对齐
space-between : 与交叉轴两端对齐,item之间间隔相等
space-around : item两侧的间隔相等,item与边框的间隔小
stretch(默认值) : 轴线占满整个交叉轴
6个item属性
order
item的排列顺序
flex-grow
item的放大比例
flex-shrink
item的缩小比例
flex-basis
item占据的主轴空间
flex
flex-grow || flex-shrink || flex basis
align-self
允许单个项目有与其他item不一样的对齐方式,可覆盖align-items属性。默认值auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch
卡顿的原因
VSync信号来
系统图形服务通过CADisplayLink(定时器)机制通知App
App主线程开始在CPU中计算显示内容,比如视图的创建,
布局计算,图片解码,文本绘制等.
随后CPU将计算好的内容提交给GPU去,GUP进行变化,合成,
渲染,随后GPU会把渲染结果提交到帧缓冲区
等待下一次VSync信号到来时显示到屏幕上.由于垂直同步的机制
如果在一个VSync时间内,CPU或者GPU没有完成内容提交,则那
一帧就会被丢弃,等待下一次机会再显示.这时显示器会保留之前的
内容不变,这就是界面卡顿的原因.
CPU资源消耗的原因和解决方案
1 对象创建 (分配内存,调整属性,读取文件 ,通过storyboard创建 视图对象时,其资源消耗会比直接通过代码创建对象要大非常多)
2 对象调整 (frame/bounds/transform) CALayer属性映射来的
3 对象消耗
4 布局计算
5 Autolayout
6 文本计算
计算文本高度[NSAttributedString boundingRectWithSize:options:context:]
绘制文本 [NSAttributedString drawWithRect:options:context:]
7 文本渲染
TextKit CoreText 对文本异步渲染
CoreText 对象创建好后能直接获取文本的宽高等信息,避免了多次计算(调整 UILabel 大小时算 一遍、UILabel 绘制时内部再算一遍)
8 图片解码
9 图片绘制
GPU资源消耗原因和解决方案
GPU干的事情
1接收提交的纹理(Texture) 和顶点描述(三角形模拟的矢量图形)
2应用变换(transform)
3混合并渲染
4输出到屏幕
纹理的渲染
所有的 Bitmap,包括图片、文本、栅格化的内容,最终都要由内存提交到显存,绑定为 GPU Texture。不论是提交到显存的过程,还是 GPU 调整和渲染 Texture 的过程,都要消耗不少 GPU 资源。当在较短时间显示大量图片时(比如 TableView 存在非常多的图片并且快速滑动 时),CPU 占用率很低,GPU 占用非常高,界面仍然会掉帧。避免这种情况的方法只能是尽量 减少在短时间内大量图片的显示,尽可能将多张图片合成为一张进行显示。
当图片过大,超过 GPU 的最大纹理尺寸时,图片需要先由 CPU 进行预处理,这对 CPU 和 GPU 都会带来额外的资源消耗。目前来说,iPhone 4S 以上机型,纹理尺寸上限都是 4096×4096,所以,尽量不要让图片和视图的大小超过这个值。
视图的混合
当多个视图(或者说 CALayer)重叠在一起显示时,GPU 会首先把他们混合到一起。如果视图 结构过于复杂,混合的过程也会消耗很多 GPU 资源。为了减轻这种情况的 GPU 消耗,应用应 当尽量减少视图数量和层次,并在不透明的视图里标明 opaque 属性以避免无用的 Alpha 通道 合成。
图形的生成
CALayer 的 border、圆角、阴影、遮罩(mask),CASharpLayer 的矢量图形显示,通常会 触发离屏渲染(offscreen rendering),而离屏渲染通常发生在 GPU 中。当一个列表视图中出 现大量圆角的 CALayer,并且快速滑动时,可以观察到 GPU 资源已经占满,而 CPU 资源消耗 很少
AsyncDisplayKit(ASDK)
基本原理
Layout 文本宽高计算,视图布局计算
Rendering 文本渲染,图片解码,图形绘制
UIKit Objects 对象创建,对象跳转,对象销毁
ASDK 认为,阻塞主线程的任务,主要分为上面这三大类。文本和布局的计算、渲染、解码、绘制都可以通过各种方式异步执行,但 UIKit 和 Core Animation 相关操作必需在主线程进行。ASDK 的目标,就是尽量把这些任务从主线程挪走,而挪不走的,就尽量优化性能
ASDK对UIKit组件进行封装
ASDK把布局计算,文本排版,图片/文本/图形渲染等封装成较小的
任务,并利用GCD异步并发执行.
Runloop任务分发 (ASDK核心技术)
VSync -> IPC -> APP (Runloop CFRunLoopSource 接收时钟信号通知) -> CoreAnimation(Runloop)
微博Demo性能优化技巧
预排版
预渲染 圆形
异步绘制 在显示文本的控件上
想要了解 ASDK 的原理和细节,最好从下面几个视频开始:
2014.10.15 NSLondon – Scott Goodson – Behind AsyncDisplayKit
2015.03.02 MCE 2015 – Scott Goodson – Effortless Responsiveness with AsyncDisplayKit
2015.10.25 AsyncDisplayKit 2.0: Intelligent User Interfaces – NSSpain 2015
学会用 Instument查看CPU与GPU
做性能优化时,也最好是走修改代码 -> Profile -> 修改代码这样一个流程
instrument
Leaks(泄漏) : 一般的查看内存使用情况,检查泄漏的内存,并提供所有活动的分配和泄漏模块的类对象 分配统计信息
Timer Profile :分析代码的执行时间,找出导致程序变慢的原因
Allocations(内存分配)
Activity Monitor(活动监视器)
Automation(自动化) 这个模板执行它模拟用户界面交互为iOS应用从instrument启动的脚步
Core Data :监听读取,缓存未命中,保存等操作,能直观显示是否保存次数远超实际需要
Cocoa Layout:观察约束变化,找出布局代码的问题所在
Network: 跟着TCP/IP 和UDP/IP连接