一、UITableView相关的数据源同步问题,即如何在tableview解决多线程情况下,数据的处理?
1、并行访问,数据拷贝;
2、串行访问。
二、是否遇到过卡顿和掉帧的问题,如何解决的,为什么出现卡顿和掉帧的问题
首先卡顿是在规定的的16.7ms之内,下一帧sync信号到来之前,并没有CPU和GPU共同完成下一帧页面的合成,于是就会造成卡顿、掉帧。
滑动优化方案:
CPU:
1、处理对象的创建、调整、销毁工作
2、预排版(布局计算、文本计算)
3、预渲染(文本等异步绘制、图片解码等)
GPU:
1、纹理渲染
2、视图混合
三、理解离屏渲染
GPU屏幕渲染有以下两种方式:
1、当前屏幕渲染(On-Screen Rendering
),指的是在当前屏幕缓冲区内进行渲染
2、离屏渲染(Off-Screen Rendering
),指的是在当前屏幕缓冲区以外新开辟的一个缓冲区进行渲染操作
离屏渲染:
当我们处理图层的属性在被指定为未被预合成之前不能直接在屏幕上显示,就触发了离屏渲染,离屏渲染的概念起源于GPU层面,指的是GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。
四、离屏渲染何时被触发?
1、圆角(当和maskToBounds
一起使用时,单独的圆角不触发)
2、图层蒙版
3、阴影
4、光栅化
5、渐变
特殊的离屏渲染:
CPU渲染,如果我们重写了drawRect
方法,并且使用任何Core Graphics
的技术进行了绘制操作,就涉及到了CPU渲染。整个渲染过程由CPU在App内同步地完成,渲染得到的Bitmap最后再交由GPU用于显示。
要尽量避免使用离屏渲染:
1、上下文切换,GPU需要额外的开销
2、创建新的渲染缓冲区,内存消耗
高级回答:
触发离屏渲染会增加GPU的工作量,而增加了GPU的工作量很有可能导致CPU和GPU的工作总耗时超过了16.67ms,从而造成页面的卡顿和掉帧。
五、使UITableView滑动更流畅的方案或思路都哪些?
(1)复用单元格
(2)使用不透明的视图,单元格中少使用动画
(3)图片使用异步加载,设置图片加载的并发数
(4)滑动时不加载图片,停止滑动时再加载
(5)图片和文字可以直接drawRect
(6)如果cell是动态行高,计算缓存单元格高度
(7)尽量少reloadData
,只用reloadRowsAtIndexPaths
(8)cell高度固定直接用rowHeight属性设置高度
六、CALayer与UIView有什么区别?
(1)UIView
是iOS系统中界面元素的继承。所有的界面元素都继承自它,他本身完全是由CoreAnimation
来实现的。它真正的绘图部分,是由一个叫CALayer
的类来管理。UIView
本身更像是一个CALayer
的管理器,访问它的跟绘图和跟坐标有关的属性,如frame,bounds
等,实际上内部都是在访问它所包含的CALayer
的相关属性。
(2)UIView
有个layer属性,可以返回它的主CALayer
实例,UIView
有一个layerClass
方法,返回主layer所使用的类,UIView
的子类,可以通过重载这个方法,来让UIView
使用不同的CALayer
来显示。
(3)UIView
的CALayer
类似UIView
的子View树形结构,也可以向它的layer上添加子layer。
(4)CALayer
坐标系统与UIView
有点不一样,它多了一个anchorPoint
的属性。
(5)UIView
的layer树形在系统内部,被系统维护着三份copy:逻辑树、动画树、显示树。
(6)CALayer
默认修改属性支持隐式动画
(7)UIView
可以接受并处理事件,CALayer
不可以。
七、简单说下UITableView、UIButton、UIWindow控件的继承关系
(1)UITableView的继承关系:
UITableView->UIScrollView->UIView->UIResponder->NSObject
(2)UIButton的继承关系:
UIButton->UIControl->UIView->UIResponder->NSObject
(3)UIWindow的继承关系:
UIWindow->UIView->UIView->UIResponder->NSObject
八、我们调用[UIView setNeedsDisplay]
方法的时候,不会立马发送对应视图的绘制工作,为什么?
调用[UIView setNeedsDisplay]
后,会调用系统的同名方法[view.layer setNeedsDisplay]
方法在当前view上面打上一个脏标记。当前Runloop将要结束的时候才会调用[CALayer display]
方法,然后进入到视图真正的绘制工作当中。
九、是否知道异步绘制?如何进行异步绘制?
基于系统开的口子[layer.delegate displayLayer:]
方法。
如果实现/遵从了dispayLayer
这个方法,我们就可以进行绘制。里面需要做:
1)代理负责生产对应的Bitmap
2)设置bitmap作为layer.contents
属性的值
十、UITableViewCell的重用机制描述一下
在开发过程中,
- (nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;
- (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
有这两个方法调起UITableViewCell的重用机制,在tableView新建的时候,会新建一个复用池,这个复用池在OC底层可能是一个队列,保存着当前cell.pool中的复用标识符就是reuseIdentifier
,标识着不同种类的cell,所以当我们调用dequeueReusableCellWithIdentifier
时,会通过当前reuseIdentifier
查找到对应的cell,也就是展示的原型。
在创建tableView的时候,会创建一个空的复用池,然后在tableView内部对pool进行管理,一般有两种用法,一种是取出一个空的cell的时候再去创建新的cell,另外一种是预先注册cell,之后再直接从复用池取出来用,不需要初始化。
对于第一种用法:第一次调用tableView:cellForRowAtIndexPath
由于复用池是空的,会首先创建cell添加到复用池中,第二次调用,当前复用池中有一个cell,这时候因为tableView上面还未填满,而且复用池的唯一的那个cell已经在使用了,所以取出来的cell仍然为nil,于是继续新建一个cell并返回,复用池再添加一个cell,当前复用池中cell的个数为2。假如当前tableView只能容纳5个cell。那么在滚动到第6个cell时,从tableView的复用池取出来的cell将会是第0行的那个cell。以此类推,当滚动到第7行时,会从复用池取出来第1行的那个cell。 另外,此时不再继续往复用池添加新的cell。
网友评论