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

UIViewController的生命周期详解

/*

两种情况下走该方法

1、主动调用

2、调用init方法之后

*/

– (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil;

 

ViewController是上层视图ViewController1是push过去的二级视图。我们可以看到ViewController1从初始化到释放的整个过程。

  1. + (void)initialize:函数并不会每次创建对象都调用,只有在第一次初始化的时候才会调用,再次创建将不会调用initialize方法。
  2. init方法和initWithCoder方法相似,只是被调用的环境不一样。如果用代码初始化,会调用init方法,从nib文件或者归档(xibstoryboard)进行初始化会调用initWithCoderinitWithCoderNSCoding协议中的方法,NSCoding是负责编码解码,归档处理的协议。
  3. loadView:是开始加载view的起始方法,除非手动调用,否则在ViewController的生命周期中只调用一次。
  4. viewDidLoad:是我们最常用的方法,类成员对象和变量的初始化我们都会放在这个方法中。在创建类后无论视图展现还是消失,这个方法也只会在布局是调用一次。
  5. viewWillAppear:(BOOL)animated:方法 是在视图将要展现出来的时候调用。
  6. viewWillLayoutSubviews:方法是在将要布局子视图的时候调用。
  7. viewDidLayoutSubviews:方法是在子视图布局完成后调用。
  8. viewDidAppear:(BOOL)animated:方法是视图已经出现。
  9. viewWillDisappear:(BOOL)animated:方法是视图即将消失。
  10. viewDidDisappear:(BOOL)animated:视图已经消失。
  11. deallocViewController被释放时调用。

总结

从上面的打印我们可以看到ViewController的整个生命周期,从初始化到被释放。其中在退出ViewController控制器的时候可以看到程序会先调用ViewControllerviewWillDisappear:(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方法进行界面元素的初始化

  

版权声明:本文为素染年华原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/liyonghua/p/8202937.html