UIView绘制原理
首先看一幅流程图
imageUIView
调用setNeedsDisplay
方法后,实际上并没有发生当前视图的绘制工作,而是在之后的某一时机进行绘制工作,为什么会在之后的某一时机进行绘制工作呢?
当UIView
调用setNeedDisplay
之后,系统会调用view
对应layer
的 setNeedsDisplay
方法,相当于在当前layer上打上了一个脏标记,然后会在当前runloop
即将结束的时候调用CALayer
的display
方法,才会真正的进入当前视图的绘制流程当中,所以视图的绘制时机,是在当前runloop
即将结束的时候才会开始.
CALayer
的display
方法的内部实现,首先会判断layer
的delegete
是否响应display
方法,如果代理不响应就会进入到系统的绘制流程当中,如果响应,实际上就为我们提供了异步绘制的接口,这样就构成了UIView的绘制原理
系统的绘制流程
同样看一副流程图
image首先CALayer
会在内部创建一个backing store(CGContextRef)
,我们一般在drawRect
中可以通过上下文堆栈当中拿到当前栈顶的context
.然后layer
判断是否有代理,如果没有代理会调用layer
的drawInContext
方法,如果实现了代理就会调用delegete
的drawLayer:inContext
方法,这是在发生在系统内部当中的,然后在合适的时机给予回调方法,也就是View
的drawRect
方法.可以通过drawRect
方法做一些其他的绘制工作.然后无论哪两个分支,都有calayer
上传backing store
(最终的位图)到GPU
.然后结束系统的绘制流程.
异步绘制
怎么进行异步绘制呢,其实就是基于系统给我们开的口子layer.delegate
,如果遵从或者实现了displayLayer
方法,我们就可以进入到异步绘制流程当中,在异步绘制的过程当中
- 就由
delegete
去负责生成bitmap
位图 - 设置改
bitmap
作为layer.content
属性的值
通过一副时序图来了解异步绘制的机制和流程
image二、UIView被添加的打印流程
1561101703.564992: <SDBaseView.m:(53)> view_willMoveToSuperview
1561101703.565066: <SDBaseView.m:(57)> view_didMoveToSuperview
1561101703.565670: <SDBaseView.m:(61)> view_willMoveToWindow
1561101703.565735: <SDBaseView.m:(66)> view_didMoveToWindow
1561101703.568001: <SDBaseView.m:(30)> view_setNeedsLayout
1561101703.568036: <SDBaseView.m:(39)> view_layoutSubviews
1561101703.568066: <SDBaseView.m:(39)> view_layoutSubviews
1561101703.568289: <SDBaseView.m:(25)> view_drawRect
1561101704.646497: <SDButtonViewController.m:(32)> 开始removeView..
1561101787.014087: <SDBaseView.m:(53)> view_willMoveToSuperview
1561101787.014245: <SDBaseView.m:(61)> view_willMoveToWindow
1561101787.014495: <SDBaseView.m:(66)> view_didMoveToWindow
1561101787.014518: <SDBaseView.m:(57)> view_didMoveToSuperview
1561101787.014560: <SDBaseView.m:(71)> view_removeFromSuperview
didMoveToWindow 不管删除还是添加 都会调用
网友评论