1. 首先UIView可以响应事件,Layer不可以.
UIKit使用UIResponder作为响应对象,来响应系统传递过来的事件并进行处理。在 UIResponder中定义了处理各种事件和事件传递的接口。
UIApplication、UIViewController、UIView、和所有从UIView派生出来的UIKit类(包括UIWindow)都直接或间接地继承自UIResponder类。
CALayer直接继承 NSObject,并没有相应的处理事件的接口。
- UIView是CALayer的delegate
- UIView主要处理事件,CALayer负责绘制就更好
-
每个 UIView 内部都有一个 CALayer 在背后提供内容的绘制和显示,并且 UIView 的尺寸样式都由内部的 Layer 所提供。两者都有树状层级结构,layer 内部有 SubLayers,View 内部有 SubViews.但是 Layer 比 View 多了个AnchorPoint
关系图.png
这是常见的 UIView 和 CALayer 的关系:View 持有 Layer 用于显示,View 中大部分显示属性实际是从 Layer 映射而来;Layer 的 delegate 在这里是 View,当其属性改变、动画产生时,View 能够得到通知。UIView 和 CALayer 不是线程安全的,并且只能在主线程创建、访问和销毁。
应用
预排版
当获取到 API JSON 数据后,我会把每条 Cell 需要的数据都在后台线程计算并封装为一个布局对象 CellLayout。CellLayout 包含所有文本的 CoreText 排版结果、Cell 内部每个控件的高度、Cell 的整体高度。每个 CellLayout 的内存占用并不多,所以当生成后,可以全部缓存到内存,以供稍后使用。这样,TableView 在请求各个高度函数时,不会消耗任何多余计算量;当把 CellLayout 设置到 Cell 内部时,Cell 内部也不用再计算布局了。
对于通常的 TableView 来说,提前在后台计算好布局结果是非常重要的一个性能优化点。为了达到最高性能,你可能需要牺牲一些开发速度,不要用 Autolayout 等技术,少用 UILabel 等文本控件。但如果你对性能的要求并不那么高,可以尝试用 TableView 的预估高度的功能,并把每个 Cell 高度缓存下来
预渲染
微信的头像在某次改版中换成了圆形,所以我也跟进了一下。当头像下载下来后,我会在后台线程将头像预先渲染为圆形并单独保存到一个 ImageCache 中去。
对于 TableView 来说,Cell 内容的离屏渲染会带来较大的 GPU 消耗。在 Twitter Demo 中,我为了图省事儿用到了不少 layer 的圆角属性,你可以在低性能的设备(比如 iPad 3)上快速滑动一下这个列表,能感受到虽然列表并没有较大的卡顿,但是整体的平均帧数降了下来。用 Instument 查看时能够看到 GPU 已经满负荷运转,而 CPU 却比较清闲。为了避免离屏渲染,你应当尽量避免使用 layer 的 border、corner、shadow、mask 等技术,而尽量在后台线程预先绘制好对应内容。
网友评论