iOS_2022_简单介绍UIViewController&UIView
UI篇-VC的生命周期以及UIView的layoutSubviews和drawRect方法 ❤️
一、UIView
layer上图形绘制见:iOS_2022_CALayer
layoutSubviews在以下情况下会被调用:
1、init初始化不会触发layoutSubviews。
2、addSubview会触发layoutSubviews。
3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。
4、滚动一个UIScrollView会触发layoutSubviews。
5、旋转Screen会触发父UIView上的layoutSubviews事件。
6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
7、直接调用setLayoutSubviews
drawRect在以下情况下会被调用:
1、如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。drawRect 掉用是在Controller->loadView, Controller->viewDidLoad 两方法之后掉用的.所以不用担心在 控制器中,这些View的drawRect就开始画了.这样可以在控制器中设置一些值给View(如果这些View draw的时候需要用到某些变量 值).
2、该方法在调用sizeToFit后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
3、通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
4、直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0。以上1,2推荐;而3,4不提倡
drawRect方法使用注意点:
1、 **若使用UIView绘图,只能在drawRect:方法中获取相应的contextRef并绘图。如果在其他方法中获取将获取到一个invalidate 的ref并且不能用于画图**。**drawRect:方法不能手动显示调用,必须通过调用setNeedsDisplay 或 者 setNeedsDisplayInRect,让系统自动调该方法。强行调用也不会起作用的。**
2、**若使用calayer绘图,只能在drawInContext: 中(类似鱼drawRect)绘制**,或者在delegate中的相应方法绘制。同样也是调用setNeedDisplay等间接调用以上方法
3、**若要实时画图,不能使用gestureRecognizer,只能使用touchbegan等方法来掉用setNeedsDisplay实时刷新屏幕。**
UIView的setNeedsDisplay和setNeedsLayout方法。
首先两个方法都是异步执行的。setNeedsDisplay会调用 drawRect方法,这样可以拿到UIGraphicsGetCurrentContext,就可以画画。 setNeedsLayout会默认调用layoutSubViews,就可以处理子视图中的一些数据。
**综上两个方法都是异步执行的,layoutSubviews方便数据计算,drawRect方便视图重绘。UIView中方法的执行顺序大概是这样的:
init 方法 >>属性的set/get 方法>> layoutSubviews(当然是要达到触发条件)>>drawRect, 使用得当可以在View的调用中起到很好的效果。
二、UIViewController
两种情况下走该方法
1、主动调用
2、调用init方法之后
*/
– (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil;
ViewController
是上层视图ViewController1
是push过去的二级视图。我们可以看到ViewController1
从初始化到释放的整个过程。
+ (void)initialize
:函数并不会每次创建对象都调用,只有在第一次初始化的时候才会调用,再次创建将不会调用initialize
方法。init
方法和initWithCoder
方法相似,只是被调用的环境不一样。如果用代码初始化,会调用init
方法,从nib文件或者归档(xib
、storyboard
)进行初始化会调用initWithCoder
。initWithCoder
是NSCoding
协议中的方法,NSCoding
是负责编码解码,归档处理的协议。loadView
:是开始加载view
的起始方法,除非手动调用,否则在ViewController
的生命周期中只调用一次。viewDidLoad
:是我们最常用的方法,类成员对象和变量的初始化我们都会放在这个方法中。在创建类后无论视图展现还是消失,这个方法也只会在布局是调用一次。viewWillAppear:(BOOL)animated
:方法 是在视图将要展现出来的时候调用。viewWillLayoutSubviews
:方法是在将要布局子视图的时候调用。viewDidLayoutSubviews
:方法是在子视图布局完成后调用。viewDidAppear:(BOOL)animated
:方法是视图已经出现。viewWillDisappear:(BOOL)animated
:方法是视图即将消失。viewDidDisappear:(BOOL)animated
:视图已经消失。dealloc
:ViewController
被释放时调用。
总结
从上面的打印我们可以看到ViewController
的整个生命周期,从初始化到被释放。其中在退出ViewController
控制器的时候可以看到程序会先调用ViewController
的viewWillDisappear:(BOOL)animated
方法然后会调用上一级视图的viewWillAppear:(BOOL)animated
方法,然后才会调用当前视图的viewDidDisappear:(BOOL)animated
方法。
2019-05-21 09:29:41.532655+0800 ThinTableVIew1[77845:3751647] ======== ViewController1 类初始化方法: initialize =======
2019-05-21 09:29:41.533321+0800 ThinTableVIew1[77845:3751647] ======== ViewController1 实例初始化方法: init =======
2019-05-21 09:29:41.539746+0800 ThinTableVIew1[77845:3751647] ======== ViewController1 加载视图: loadView =======
2019-05-21 09:29:41.539975+0800 ThinTableVIew1[77845:3751647] ======== ViewController1 将要加载视图: viewDidLoad =======
2019-05-21 09:29:41.540280+0800 ThinTableVIew1[77845:3751647] ======== ViewController1 视图将要出现: viewWillAppear:(BOOL)animated =======
2019-05-21 09:29:41.581539+0800 ThinTableVIew1[77845:3751647] ======== ViewController1 将要布局子视图: viewWillLayoutSubviews =======
2019-05-21 09:29:41.581755+0800 ThinTableVIew1[77845:3751647] ======== ViewController1 已经布局子视图: viewDidLayoutSubviews =======
2019-05-21 09:29:42.086186+0800 ThinTableVIew1[77845:3751647] ======== ViewController1 视图已经出现: viewDidAppear:(BOOL)animated =======
2019-05-21 09:30:11.567953+0800 ThinTableVIew1[77845:3751647] ======== ViewController1 视图将要消失: viewWillDisappear:(BOOL)animated =======
2019-05-21 09:30:11.568210+0800 ThinTableVIew1[77845:3751647] ======== ViewController 视图将要出现: viewWillAppear:(BOOL)animated =======
2019-05-21 09:30:12.074866+0800 ThinTableVIew1[77845:3751647] ======== ViewController1 视图已经消失: viewDidDisappear:(BOOL)animated =======
2019-05-21 09:30:12.075103+0800 ThinTableVIew1[77845:3751647] ======== ViewController 视图已经出现: viewDidAppear:(BOOL)animated =======
2019-05-21 09:30:12.075378+0800 ThinTableVIew1[77845:3751647] ======== ViewController1 释放: dealloc =======
========================================
2022/7/22更新—-如上
========================================
总结:vc/view 通过sb/xib初始化会走awakeFromNib
常用:cell通过xib生成,做一些初始化操作
1、vc通过sb初始化
initWithCoder awakeFromNib loadView viewDidLoad
2、vc通过xib初始化
a、[[类 alloc] initWithNibName:类名字符串 bundle:nil]
initWithNibName:类名字符串 bundle:nil loadView viewDidLoad
b、[[类 alloc] init]
init loadView viewDidLoad
c、 [[类 alloc] initWithFrame:]
initWithFrame loadView viewDidLoad
d、vc未通过xib略
3、view
init/initWithFrame drawRect
4、cell通过xib
initWithCoder awakeFromNib
loadView viewDidLoad viewDidUnload(已弃用) 关系
1.第一次访问UIViewController的view时,view为nil,然后就会调用loadView方法创建view
2.view创建完毕后会调用viewDidLoad方法进行界面元素的初始化
3.当内存警告时,系统可能会释放UIViewController的view,将view赋值为nil,并且调用viewDidUnload(已弃用)方法
4.当再次访问UIViewController的view时,view已经在3中被赋值为nil,所以又会调用loadView方法重新创建view
5.view被重新创建完毕后,还是会调用viewDidLoad方法进行界面元素的初始化