UI视图重点

1.TabelView

1)为什么使用重用机制

无论是TableView还是CollectionView,每次多会加载很多的Cell(item),每次都全部加载而屏幕上又只能显示几个,会造成内存的极大浪费。

2)重用机制的原理

重用机制实现了数据和显示的分离,并不会为每个要显示的数据都创建一个Cell,一般情况下只创建屏幕可显示的最大的cell个数+1,每当有一个cell从屏幕消失,就将其放到缓存池中,如果有新的cell出现,就去缓存池中取,如果缓存池中没有,再创建。

3)如何避免Cell中数据重复显示问题

  • cell从缓存池中取出的时候,没有对cell重新赋值,导致cell仍然显示之前的数据。在取出cell后,进行重新赋值,如果需要根据判断显示子视图或者某些数据,所做的判断要充分,如:
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //列出可重用的cell
if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (条件成立){
        cell.icon.hidden = Yes;
        cell.name.text = @"1";
}else{//此处判断不充分(即没有else)将会导致数据或子视图的混乱
        cell.icon.hidden = NO;
        cell.name.text = @"2";
}
[cell reloadWithModel:model];//给cell添加reloadWithModel方法,从重用池取出cell后重新进行赋值操作。

注:不建议取消重用机制的方法,笔者发现重用混乱皆因tableView源数据混乱或cell赋值问题导致,找到赋值cell的代码重新检查,改变cell的显示,先改变数据源,在刷新cell,如有UITextField,其值在model中记录,可避免这些显示问题。

优化TableView

尽量少用或不用透明图层
如果Cell内现实的内容来自web,使用异步加载,缓存请求结果
减少subviews的数量
尽量少用addView给Cell动态添加View,可以初始化时就添加,然后通过hide来控制是否显示
提前计算并缓存好高度(布局),因为heightForRowAtIndexPath:是调用最频繁的方法;
缓存图片SDWebImage
性能优化要注意平衡CPU和GPU的负载

  • 如何在tableView解决多线程情况下,数据的处理

并发访问,数据拷贝
串行访问

2.事件传递&视图响应

UIView和CALayer

UIView和CALayer体现了单一职责的设计概念;
CALayer负责图层的绘制;UIView负责提供内容及处理触摸事件,参与响应者链。

事件的传递

1.首先判断主窗口(keyWindow)自己是否能接受触摸事件
2.触摸点是否在自己身上
3.从后往前遍历子控件,重复前面的两个步骤(首先查找数组中最后一个元素)
4.如果没有符合条件的子控件,那么就认为自己最合适处理

响应者链

UIApplication-->UIWindow-->递归找到最合适处理的控件-->控件调用touches方法-->判断是否实现touches方法-->没有实现默认会将事件传递给上一个响应者-->找到上一个响应者-->找不到方法作废

整个过程:

触摸或者点击一个控件,然后这个事件会从上向下(从父->子)找最合适的view处理,找到这个view之后看他能不能处理,能就处理,不能就按照事件响应链向上(从子->父)传递给父控件

事件传递和响应的区别:

事件的传递是从上到下(父控件到子控件),事件的响应是从下到上(顺着响应者链条向上传递:子控件到父控件。

hitTest:withEvent:方法

什么时候调用?
只要事件一传递给一个控件,这个控件就会调用他自己的hitTest:withEvent:方法寻找合适的View
作用
寻找并返回最合适的view(能够响应事件的那个最合适的view)
注 意:不管这个控件能不能处理事件,也不管触摸点在不在这个控件上,
事件都会先传递给这个控件,随后再调用hitTest:withEvent:方法
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
该方法判断触摸点是否在控件身上, 是则返回YES, 否则返回NO

3.iOS图像显示原理

硬件层面的调度

UI视图重点_第1张图片
计算机图像显示原理

计算机系统中 CPU、GPU、显示器是以上面这种方式协同工作的。CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示。

iOS绘图框架结构

UI视图重点_第2张图片
iOS图形框架

iOS图像的显示原理(软件层面)

UI视图重点_第3张图片
iOS图像显示原理

4.卡顿和掉帧

UI视图重点_第4张图片
卡顿和掉帧

如上图第二帧所示(CPU和GPU所花时间超过了16.7ms),如果在一个 VSync 时间内,CPU 或者 GPU 没有完成内容提交,则那一帧就会被丢弃,等待下一次机会再显示,而这时显示屏会保留之前的内容不变。这就是界面卡顿的原因。

滑动优化方案

CPU:
1.对象的创建、调整、销毁
2.预排版(布局计算、文本计算)
3.预渲染(文本等异步绘制、图片编码等);
GPU:
1.纹理渲染
2.视图混合

5.iOS绘制原理&异步绘制

绘制原理

UI视图重点_第5张图片
系统绘制原理流程图

首先,CALayer会在内部创建一个backing store(CGContextRef),我们一般在drawRect中可以通过上下文堆栈当中拿到当前栈顶的context,然后layer判断是否有代理,如果没有代理会调用layer的drawInContext方法,如果实现了代理就会调用delegate的drawLayer:inContext方法,这是发生在系统内部当中的,然后再合适的时机给与回调方法,也就是view的drawRect方法,可以通过drawRect方法做一些其他的绘制工作,然后无论哪两个分支,都有CALayer上传backing store(最终的位图)到CPU,最后结束系统的绘制流程。

异步绘制

UI视图重点_第6张图片
异步绘制时序图

异步绘制,是基于layer.delegate实现的,遵从代理并实现了displayLayer方法,我们就可以进入到异步绘制流程当中,在异步绘制的过程当中:
1.由delegate去负责生成bitmap位图。
2.设置改bitmap作为layer.content属性的值。

6.离屏渲染

概念

当我们处理图层的属性在被指定为未被预合成之前不能直接在屏幕上显示,就触发了离屏渲染。离屏渲染的概念起源于GPU层面,指的是GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。

触发时机

1.圆角(当和maskToBounds一起使用时)
2.图层蒙版
3.阴影
4.光栅化

为何避免

1.上下文切换,GPU额外的开销
2.创建新的渲染缓冲区,内存消耗
3.高级回答:触发离屏渲染会增加GPU的工作量,而增加了GPU的工作量很可能导致CPU和GPU的工作总耗时超过了16.67ms,有可能导致UI的卡顿和掉帧

部分内容来源于网络;
文章仅个人笔记记录分享,欢迎指教。

你可能感兴趣的:(UI视图重点)