UIViewController生命周期和LayoutSubview的一些特殊情况

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_44865905/article/details/101578171

一 . LoadView和ViewDidLoad的死循环问题

解决By赵冬学长

  • 问题起源:

    LoadView里面加载ViewController的view,当调用self.view(ViewController的view)时,如果View为空, 那就会走LoadView去加载view, 所以, 当LoadView中没有实现加载View的功能, 就会陷入Loadview和viewDidLoad死循环。
  • 代码

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)loadView {
   NSLog(@"loadView");
}

- (void)viewWillAppear:(BOOL)animated {
   NSLog(@"viewWillAppear");
}

- (void)viewDidLoad {
//    [super viewDidLoad];
   NSLog(@"viewDidLoad");
   // Do any additional setup after loading the view.
}


@end
  • 结果:

(Xcode版本10.14.6)

问题描述

(之前版本)
问题描述
这里只走两次, 代码同上

问题:

1. 为什么会结果不同, 以及为什么LoadView和ViewDidLoad的循环中会出现ViewWillAppear?

(旧版本)
根据打印顺序推测, 应该是Xcode系统的一种防护机制, 当到viewDidLoad时View为空, 此时viewDidLoad中只有

[super viewDidLoad];
NSLog(@"ViewDidLoad"); 

viewDidLoad完成后, 检测到view为空, 会再调用一次LoadView, 当再次回到ViewDidLoad,发现view还为空时, 系统就会启动防护机制, 阻止再次回到LoadView, 所以结果中, 在两次循环后便停止了循环。

经学长提醒,这种防护机制并非在[super ViewDidLoad]中实现, 我在viewDidLoad中再加一句, 现在代码如下

[super viewDidLoad];
self.view.backgroundColor = [UIColor orangeColor];
NSLog(@"ViewDidLoad"); 

会进入死循环和报错(见下图)他陷入死循环说明走到了self.view这一句(LoadView本来就会因为self.view触发), 那么说明, 这种防护机制在viewDidLoad中实现, 并非在[super viewDidLoad]中实现。

至于[super viewDidLoad]所执行的操作, 我找到的解释是:

以viewDidLoad为例,父类(super)中的viewDidLoad会帮助你做一些初始化的工作,比如A是父类,B继承A,B在viewDidLoad方法中创建和初始化了一些成员;C又继承B,此时,如果C在调用viewDidLoad的时候没有调用super的viewDidLoad方法,那么就会有一些成员没有被初始化,可能就会产生问题。
在这里插入图片描述(新版本中)
在新版本中, 结果代码变长了, 但简单分析可知, 这也是Xcode系统优化后的防护机制。

二. Memory Wranning(内存警告)问题

当内存不足以运行当前ViewController时, 就会通过该方法释放其他与view有关的对象、其他在运行时创建(但非系统必须)的对象、在viewDidLoad中被创建的对象、缓存数据等。现在的viewController就相当于LoadView刚结束时的样子。 但他并不意味着走到LoadView刚结束, 也不会再继续走ViewDidLoad,然后死循环。

3. 屏幕旋转触发LayoutSubview问题

解决By李飞艳学姐

在layoutSubview的触发测试中, 我们发现本来给view设置frame触发一次layoutSubview, 但应为初始位置的不同, 以及大小的不同, 触发次数也会不同, 此时会触发layoutSubview的只有设置frame, 当frame为(100, 100, 100, 100)时正常触发一次。

扫描二维码关注公众号,回复: 7634557 查看本文章

首先控制单一变量, 让位置定在(100, 100)

当宽和高钧为0时, 系统才认为大小为0, 此时不打印; 高和宽一个为0, 一个不为0时, 也会认为大小不为0, 打印一次。

其次让大小为(100, 100)

我们发现当他的位置设为(10, 10)时, 当他旋转时, 会触发layoutSubview, 但按理来说他大小不变, 应该不会触发, 当改变位置为(50, 50)时, 再次运行, 就不会触发。
多次测验后, 发现一临界值20, 而模拟机状态栏的长度刚好为20, 所以, 可知这于状态栏有一定联系。
模拟机旋转时, 只有home键在手机下方那个方向时有状态栏, 所以只要设置的view不和状态栏有重合, 就不会触发layoutSubViews(屏幕大小不改变的前提下)。
自定义的view的大小超过屏幕尺寸也不会触发, 以iPhone7为例, 竖屏为375667(宽高), 横屏为667*375, 如果自定义的view的frame为(50, 50, 50, 400), 当竖屏时并不会超出屏幕, 横屏时会超出屏幕, 但并不会触发layoutSubviews。

猜你喜欢

转载自blog.csdn.net/qq_44865905/article/details/101578171