• 【iOS开发】-UIViewController加载过程和生命周期


    前言

    • 在写项目的时候,ViewController是最基本的东西,只是知道他用来加载视图,控件的全能函数,把一些控件啥的不管都写在里面去了,通过了解ViewController的生命周期发现他的内部存在许多函数

    ViewController执行过程的探讨

    • 思路:设置2个界面,采用P resent同级跳转的方法推出界面,之后在第二界面设置返回Button,每个界面的每个函数打印操作过程就能看到先后顺序了
    • 代码
    ViewControllerOne
    • 先进行一下ViewControllerOne的初始化加载,函数放到后面去讲,和平常不一样的是打印了每个函数执行过程
    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface ViewControllerSecond : UIViewController
    // Button跳转到下一界面
    @property (nonatomic, strong)UIButton* buttonReturn;
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "ViewControllerSecond.h"
    #import "Masonry.h"
    @interface ViewControllerSecond ()
    
    @end
    
    @implementation ViewControllerSecond
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        NSLog(@"%s",__func__);
        self.view.backgroundColor = [UIColor orangeColor];
        _buttonReturn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        [_buttonReturn setTitle:@"Return" forState:UIControlStateNormal];
        [_buttonReturn addTarget:self action:@selector(press) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:_buttonReturn];
        [_buttonReturn mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.mas_offset(150);
            make.left.mas_offset(200);
            make.width.mas_offset(200);
            make.height.mas_offset(100);
        }];
    }
    - (void)loadView {
        [super loadView];
        NSLog(@"%s",__func__);
    }
    - (void)viewWillAppear:(BOOL)animated {
        NSLog(@"%s",__func__);
    }
    - (void)viewWillLayoutSubviews {
        NSLog(@"%s",__func__);
    }
    - (void)viewWillDisappear:(BOOL)animated {
        NSLog(@"%s",__func__);
    }
    - (void)viewDidAppear:(BOOL)animated {
        NSLog(@"%s",__func__);
    }
    - (void)viewDidLayoutSubviews {
        NSLog(@"%s",__func__);
    }
    - (void)viewDidDisappear:(BOOL)animated {
        NSLog(@"%s",__func__);
    }
    - (void)press {
        NSLog(@"-------------Second is Back!--------------");
        [self dismissViewControllerAnimated:YES completion:nil];
        
    }
    
    /*
    #pragma mark - Navigation
    
    // In a storyboard-based application, you will often want to do a little preparation before navigation
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
        // Get the new view controller using [segue destinationViewController].
        // Pass the selected object to the new view controller.
    }
    */
    
    @end
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 执行第一界面的加载请添加图片描述
    函数介绍
    • 结果:从上到下一次打印了VIew执行过程函数
    • viewDidLoad:在视图加载后被调用,如果是在代码中创建的视图加载器,他将会在loadView方法后被调用,如果是从nib视图页面输出,他将会在视图设置好后后被调用。只会被调用一次,之后进入这个ViewController不调用此函数
    • loadView:每次访问controller的view(比如controller.view、self.view)且view为nil,loadView方法就会被调用。用于创建Controller的View
    • viewWillAppear: 视图将要显示
    • viewWillLayoutSubviews: 控制器的view将要布局子控件(在这个方法里,部署需要改变重新刷新view的代码,功能类似view的layoutSubViews()这个方法,需要注意的是,这个方法里一般都需要重置的view的frame,宽度和高度的获取,因此view的frame一般都写在这个方法里)
    • viewDidLayoutSubviews: 控制器的view布局子控件完成
    • viewDidAppear: 视图已经显示
    • viewWillDisappear: 视图将要消失
    • viewDidDisappear: 视图已经消失,在Controller被切换时调用,第二个视图出现后第一个视图消失
    顺序引入
    • 我们发现上述结果只打印到了DidAppear函数,并没有出现DIss appear的两个函数,如上所述,dis appear是界面即将消失的时候出现的函数,我们并没有切换界面,所以这个函数也不会调用
    • 接下来引入界面二,看diss appear的调用位置
    ViewControllerSecond引入
    • 代码
    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface ViewControllerSecond : UIViewController
    // 返回第一界面的Button
    @property (nonatomic, strong)UIButton* buttonReturn;
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "ViewControllerSecond.h"
    #import "Masonry.h"
    @interface ViewControllerSecond ()
    
    @end
    
    @implementation ViewControllerSecond
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        NSLog(@"%s",__func__);
        self.view.backgroundColor = [UIColor orangeColor];
        _buttonReturn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        [_buttonReturn setTitle:@"Return" forState:UIControlStateNormal];
        [_buttonReturn addTarget:self action:@selector(press) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:_buttonReturn];
        [_buttonReturn mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.mas_offset(150);
            make.left.mas_offset(200);
            make.width.mas_offset(200);
            make.height.mas_offset(100);
        }];
    }
    - (void)loadView {
        [super loadView];
        NSLog(@"%s",__func__);
    }
    - (void)viewWillAppear:(BOOL)animated {
        NSLog(@"%s",__func__);
    }
    - (void)viewWillLayoutSubviews {
        NSLog(@"%s",__func__);
    }
    - (void)viewWillDisappear:(BOOL)animated {
        NSLog(@"%s",__func__);
    }
    - (void)viewDidAppear:(BOOL)animated {
        NSLog(@"%s",__func__);
    }
    - (void)viewDidLayoutSubviews {
        NSLog(@"%s",__func__);
    }
    - (void)viewDidDisappear:(BOOL)animated {
        NSLog(@"%s",__func__);
    }
    - (void)press {
        NSLog(@"-------------Second is Back!--------------");
        [self dismissViewControllerAnimated:YES completion:nil];
        
    }
    
    /*
    #pragma mark - Navigation
    
    // In a storyboard-based application, you will often want to do a little preparation before navigation
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
        // Get the new view controller using [segue destinationViewController].
        // Pass the selected object to the new view controller.
    }
    */
    
    @end
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    ViewControllerOne点击执行到ViewControllerSecond的2种情况

    • 在这里出现2种不同的情况
    • 情况一:请添加图片描述
    • 在第二界面加载出来的时候第一界面的dissappear并没有出现,后来发现我在第一界面的Button事件里面缺少了这句话
    • View.modalPresentationStyle = UIModalPresentationFullScreen;的意思是弹出并且是占据了整个屏幕,接下来加上这句话请添加图片描述请添加图片描述- 分析:看到上述结果就是一个View加载的全部过程了,首先我们得知道,控制器 view 是通过懒加载的方式进行加载的,即用到的时候再加载。,所以系统先去loadView里执行了一遍我们重写的方法[super loadView]; 接下来再去加载View

    View加载的分析

    • View加载的过程(转):在 view 加载过程中首先会调用 loadView 方法,在这个方法中主要完成一些关键 view 的初始化工作,比如 UINavigationViewController 和 UITabBarController 等容器类的 ViewController;接下来就是加载 view,加载成功后,会接着调用 viewDidLoad 方法,这里要记住的一点是,在 loadView 之前,是没有 view 的,也就是说,在这之前,view 还没有被初始化。完成 viewDidLoad 方法后,ViewController 里面就成功的加载 view了
    • 为此我做一尝试,在loadView函数里面不写[super loadView],结果如下,我吧Second View的load View函数改了,其他并未变化
    - (void)loadView {
    //    [super loadView];
        NSLog(@"%s",__func__);
    }
    
    • 1
    • 2
    • 3
    • 4

    请添加图片描述

    请添加图片描述

    • 直接看到,函数回去不断的重复的寻找View,也就是在loadView接下来到Viewdidload发现VIew为空,再次回去寻求View,如此重复若 loadView 没有加载 view,即为 nil,viewDidLoad 会一直调用 loadView 加载 view,因此构成了死循环,程序即卡死,所以我们常在 ViewDidLoad 里创建 view。

    Viewdidload之后发生地事情

    • 参考大佬博客UIViewController生命周期
    • 通过图片可以看到viewWillAppear总是出现在ViewdidLoad之后,但不是立即,当你只是引用了属性 view,却没有立即把 view 添加到任何已经展示的视图上时,viewWillAppear 不会被调用,这在 view 被外部引用时,就会发生。当然,随着 ViewController 的多次推入,多次进入子页面后返回,该方法会被多次调用。与 viewDidLoad 不同,调用该方法就说明控制器一定会显示。
    viewWillAppear 和 viewDidAppear 中间的过程

    请添加图片描述

    • viewWillLayoutSubviews- viewDidLayoutSubviews两个方法被调用了
    • viewWillLayoutSubviews
      • 该方法在通知控制器将要布局 view 的子控件时调用。每当视图的 bounds 改变,view 将调整其子控件位置。默认实现为空,可重写以在 view 布局子控件前做出改变。该方法调用时,AutoLayout 未起作用。
    • viewDidLayoutSubviews
      • 该方法在通知控制器已经布局 view 的子控件时调用。默认实现为空,可重写以在 view 布局子控件后做出改变。该方法调用时,AutoLayout 未起作用。

    viewWillDisappear 和 viewDidDisappear

    请添加图片描述

    • 在我们推出了视图二的时候,视图二的VIewdi dLoad函数完成了,出现了视图一的viewWillDisappear,而在视图二的ViewDidappear出现之后,视图一的viewDidDisappear才完成,也就是说在第二个界面加载开始到加载完成,第一个界面才会完全的消失!!

    结尾

    • 对于present和push只是简单的提了一下,present只是弹出,所以并么有全部的覆盖第一界面,今天主要了解UIView Controller的加载过程和生命周期,接下来会进一步学习present和push的区别
  • 相关阅读:
    Fragment中获取Activity的方法进行fragment的切换
    Qt学习22 布局管理器(一)
    Spark中sc.textFile()读取文件路径
    微软宣布即将停止对 Visual Studio 旧版本的支持
    剑指offer——JZ24 反转链表 解题思路与具体代码
    Django笔记三十之log日志记录详解
    浅谈路由器基本结构与工作原理
    一道python难题5
    Spark - 第13章 高级RDD
    Dubbo3应用开发——架构的演变过程
  • 原文地址:https://blog.csdn.net/weixin_61639290/article/details/126853738