1. TableView重用机制
- 重用池等待重用队列
- 主窗口正使用的队列
- 考虑重用标识检索队列取的视图
1 | import Foundation |
2. 数据源同步问题
起因:
多线程对数据源的访问
解决方案:
- 数据源拷贝; 主线程拷贝(记录增删改操作),子线程异步操作(回到主线程前同步主线程的操作记录)
- 串行访问队列; 主线程等待子线程异步操作完成后, 数据都放在串行队列中处理, 完成后再返回主线程
3. UIView和CALayer
- UIVIew为其提供内容, 以及负责处理触摸等事件,参与响应链.
- CALayer负责显示内容contents.
- 体现了单一职责原则
4. 事件传递与视图响应链
- 事件传递
1 | // 核心方法 |
- 传递流程. (找到能响应的视图)
- 先判断视图能否交互;
v.hidden && v.userInteractionEnabled && v.alpha > 0.01
- 判断是否事件位置是否在视图内, 调用
pointInside:withEvent:
- 倒序遍历(后添加的视图一般显示在视图最前面)
v.subviews
, 并调用hitTest:withEvent:
寻找能响应的视图 - 返回最终能响应的子视图
- 响应流程.
- 事件的响应由传递链最终找到的子视图先判定是否响应,
- 如不能响应, 则会由子视图的父视图再去判断能否响应,
- 依照这个规律, 一直找到最上层的
UIApplication
, - 如果仍不响应此处事件, 则这个事件将会被忽略掉
5. 图像显示原理
CPU工作:
Layout
: 布局计算;Display
: 绘制;Prepare
: 图片编解码,Commit
: 提交位图GPU渲染管线:
[顶点着色, 图元装配, 光栅化, 片段着色, 片段处理] =>FrameBuffer
UI卡顿掉帧原因: 在规定的
60FPS/16.7ms
(基于人眼而定的流畅)内, 在下一帧信号到来前, CPU和GPU协同处理下, 并没有准备好当前帧的画面.
6. 滑动优化方案
- CPU
- 对象创建, 调整, 销毁
- 预排版 (布局计算, 文本计算)
- 预渲染 (文本等异步绘制, 图片编解码等)
- GPU
- 纹理渲染 (尽量避免离屏渲染, 异步绘制[CPU])
- 视图混合 (减少视图复杂度)
7. UIView绘制原理
v.setNeedsDisplay
-> v.layer.setNeedsDisplay
-> 当前RunLoop
将要结束时 -> CALayer display
-> 内部判断是否响应 displayLayer -> (响应) 异步绘制 / (不响应) 系统绘制
- 异步绘制
- 核心方法
layer.delegate.displayLayer
- 代理负责生成对应的bitmap
- 设置该bitmap作为
layer.contents
属性的值
8. 离屏渲染
- On-Screen Rendering 当前屏幕渲染, 指的是GPU的渲染操作是在当前用于显示的屏幕缓冲区中进行
- Off-Screen Rendering 离屏渲染, 指的是GPU在当前屏幕缓冲区以外
新开辟
一个缓冲区进行渲染操作
何时触发离屏渲染?
- 圆角 (当和maskToBounds一起使用时)
- 图层蒙版
- 阴影
- 光栅化
为何要避免?
- 创建新的渲染缓存区
- 上下文切换 (多通道渲染管线)
- 触发离谱渲染, 会增加GPU的工作量, 而增加GPU的工作量, 可能会进一步导致GPU和CPU协同处理时间超过16.7ms, 此时会导致画面卡顿掉帧.
总结
1. 系统的UI事件传递机制时怎么样的?
(1). 核心方法 hitTest:
, pointInside:
(2). 传递(由上到下, 找到事件最终落在的子视图)和响应(由下到上, 找到最终能响应的视图. 注意, 如直到UIApplication不没有响应, 则事件将被忽略)链
2. UITableView滚动流畅优化方案? (性能优化相关)
(1). 管理创建, 调整, 销毁
(2). 预排版, 预渲染
3. UIView和CALayer关系
(1). UIView负责交互, 响应事件
(2). CALayer仅负责显示内容
(3). 符合单一职责设计原则
- 本文作者: 醉疏狂
- 本文链接: https://hubin97.github.io/2020/05/20/UI视图/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!