基础知识 - UI视图
tableView重用机制
tableView的重用机制,会自动创建当前可见个数+1的cell数量,这样当视图cell需要出现在视野中就根据reuseIdentifier从复用池中取出对应的cell,如果取到了就直接拿过来用,没有取到,就直接创建指定reuseIdentifier的cell,当cell移开视野后,又会把cell从当前可视数组中移除,添加到复用池中,供下次使用
具体默认会有一个可变可视数组,用来存放当前可见的cell,然后一个可变的字典用来存储所有可用cell,这些cell通过resueIdentifier为key,当cell需要显示时就从字典中通过reuseIdentifier取出cell,如果取出为nil,则重建新的cell,当视图移除可见区域,则移除区域的cell会从可视数组中移除,并添加到可用字典中,当需要用时,在添加到可视数组中,并从字典中移除
//方法一
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//方法二
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
这两个方法的区别:方法2一定会返回一个可以用cell需要配合 [self.tableView registerClass:[MeetingReplyBasicCell class] forCellReuseIdentifier:@"BasicCell"]使用
tableView线程同步
-
并发访问, 数据拷贝 【多任务轮询执行,同一时间只有一个任务被执行】
如果删除数据在主线程操作,加载数据在子线程操作,那么在子线程加载数据之前把数据源copy一份,并且标记要删除的数据,然后主线程删除数据,并刷新UI,子线程加载完数据后,先删除标记的需要删除的数据,在添加新的数据转到主线程刷新UI
缺点:需要copy,内存开销大 -
串行访问【多个任务依次执行】
假设删除数据在主线程, 加载更多在子线程A, 串行同步队列B;
- 将加载更多拿到的数据和需要删除的数据都放到队列B中;
- 串行队列中,同步执行; 加载更多和删除都完成后转到主线程刷新UI;
缺点:串行队列同步执行, 如果删除或者加载更多都很耗时的话整个过程会比较慢;
UIView
UIView和CALayer的区别
- uiview负责提供显示的内容,负责事件传递,参与响应链
- calayer只负责显示uiview提供的内容
关于UIView事件传递

点击屏幕 -> UIApplication -> UIWindow -> hitTest:withEvent: ->pointInside:withEvent:
点击屏幕事件会传递给UIApplication,UIApplication又会将事件传递给UIWindow,UIWindow会调用hitTest:withEvent返回响应的视图hitTest:withEvent实现的内部通过调用pointInside:withEvent:来判断点击的位置是否在响应的范围内,如果不在直接return nil,如果在,则遍历其子视图倒序遍历,每个子视图都调用hitTest:withEvent方法去查找是否有返回值,如果
倒序遍历 后添加的视图先被遍历
histTest:withEvent: 判断当前视图是否具备可点击可触摸 如果满足条件 则利用pointInside:withEvent判断触摸点是否在当前视图,如果再当前视图则遍历当前视图的子视图,所有的子视图调用histTest:withEvent: 最终找到hit对象并返回
图像的显示原理

CPU:UI布局,文本计算,视图绘制,图片编解码
GPU: 图层渲染,纹理合成
CPU和GPU通过总线连接起来的,CPU负责UI布局,文本计算,视图绘制和图片编解码,最终生成位图,通过管线提交给GPU,GPU拿到位图后,进行图形的渲染和纹理的合成,然后处理的结果放到帧缓冲区中(Frame Buffer),然后由视频控制器根据vsync信号,在下一个vsync信号到来之前将视图提交到显示器上,如果在在vsync信号到来之前,未能将显示的内容处理完毕,就会出现卡顿的情况
屏幕卡顿
我们知道屏幕的刷新频率一般的1/60s,我们之所以能够看到画面,那是因为CPU和GPU共同协作将视图展现在我们面前,如果cpu和GPU没有在规定的1/60时间内将图片合成,那么就会出现卡顿的情况
离屏渲染
当前屏幕渲染 GPU的渲染操作发生在当前屏幕缓冲内以外新开辟的缓冲区中,则叫离屏渲染
发生离屏渲染的原因 主要是使用圆角 阴影 遮罩等导致的
性能优化
1. 对象的创建
尽量使用轻量级的对象(UIView - CALayer)
减少对象的创建,如果可以设计复用池的方式,需要的时候拿出来用(TableView缓存池的设计方法)
对象的创建和释放放在异步线程来完成(AsyncDisplayKit 对对象进行了重新封装 对象的创建和释放在异步线程发生,并且线程安全)
减少storyboard、xib的使用,这些比纯代码跟消耗性能
2. 减少计算
使用高性能的JSON转model的方式 (YYModel、MJExtension)
需要计算的提前计算好 (微博列表高度固定的 提前计算好高度)
能确定高度的直接将高度确定下来
tableView的cell中运算要尽可能减少,如果比较耗时的操作尽量不放在主线程中
3. 位置的计算
frame的性能是最高的,如果对性能要求很严格的场景下,减少使用layout
4. 离屏渲染
减少离屏渲染的发生 减少圆角、阴影、遮罩的使用,如果需要使用,最好使用其他方案解决比如圆角可以使用Core Craphics来绘制
据说iOS9以后UIImageView 设置masksToBounds不会触发离屏渲染了

浙公网安备 33010602011771号