iOS 控制器的生命周期

一、 ARC环境

单个viewController的生命周期

initWithCoder:(NSCoder *)aDecoder:(如果使用storyboard或者xib)

loadView:加载view

viewDidLoad:view加载完毕

viewWillAppear:控制器的view将要显示

viewWillLayoutSubviews:控制器的view将要布局子控件

viewDidLayoutSubviews:控制器的view布局子控件完成

这期间系统可能会多次调用viewWillLayoutSubviews 、 viewDidLayoutSubviews 俩个方法

viewDidAppear:控制器的view完全显示

viewWillDisappear:控制器的view即将消失的时候

这期间系统也会调用viewWillLayoutSubviews 、viewDidLayoutSubviews 两个方法

viewDidDisappear:控制器的view完全消失的时候

多个viewControllers跳转

当我们点击push的时候首先会加载下一个界面然后才会调用界面的消失方法

initWithCoder:(NSCoder *)aDecoder:ViewController2(如果用xib创建的情况下)

loadView:ViewController2

viewDidLoad:ViewController2

viewWillDisappear:ViewController1将要消失

viewWillAppear:ViewController2将要出现

viewWillLayoutSubviewsViewController2

viewDidLayoutSubviewsViewController2

viewWillLayoutSubviews:ViewController1

viewDidLayoutSubviews:ViewController1

viewDidDisappear:ViewController1完全消失

viewDidAppear:ViewController2完全出现

小结:

-整个控制器声明周期:  viewDidLoad -> viewWillAppear -> viewWillLayoutSubviews -> viewDidLayoutSubviews ->  viewDidAppear -> viewWillDisappear -> viewDidDisappear

loadView()

若控制器有关联的 Nib 文件,该方法会从 Nib 文件中加载 view;如果没有,则创建空白 UIView 对象。

自定义实现不应该再调用父类的该方法。

viewDidLoad()

view 被加载到内存后调用viewDidLoad()。

重写该方法需要首先调用父类该方法。

该方法中可以额外初始化控件,例如添加子控件,添加约束。

该方法被调用意味着控制器有可能(并非一定)在未来会显示。

在控制器生命周期中,该方法只会被调用一次。

viewWillAppear(_:)

该方法在控制器 view 即将添加到视图层次时以及展示 view 时所有动画配置前被调用。

重写该方法需要首先调用父类该方法。

该方法中可以进行操作即将显示的 view,例如改变状态栏的取向,类型。

该方法被调用意味着控制器将一定会显示。

在控制器生命周期中,该方法可能会被多次调用。

注意:

如果控制器 A 被展示在另一个控制器 B 的 popover 中,那么控制器 B 不会调用该方法,直到控制器 A 清除。

viewWillLayoutSubviews()

该方法在通知控制器将要布局 view 的子控件时调用。

每当视图的 bounds 改变,view 将调整其子控件位置。

该方法可重写以在 view 布局子控件前做出改变。

该方法的默认实现为空。

该方法调用时,AutoLayout 未起作用。

在控制器生命周期中,该方法可能会被多次调用。

viewDidLayoutSubviews()

该方法在通知控制器已经布局 view 的子控件时调用。

该方法可重写以在 view 布局子控件后做出改变。

该方法的默认实现为空。

该方法调用时,AutoLayout 已经完成。

在控制器生命周期中,该方法可能会被多次调用。

viewDidAppear(_:)

该方法在控制器 view 已经添加到视图层次时被调用。

重写该方法需要首先调用父类该方法。

该方法可重写以进行有关正在展示的视图操作。

在控制器生命周期中,该方法可能会被多次调用。

viewWillDisappear(_:)

该方法在控制器 view 将要从视图层次移除时被调用。

类似 viewWillAppear(_:)。

该方法可重写以提交变更,取消视图第一响应者状态。

viewDidDisappear(_:)

该方法在控制器 view 已经从视图层次移除时被调用。

类似 viewDidAppear(_:)。

该方法可重写以清除或隐藏控件。

didReceiveMemoryWarning()

当内存预警时,该方法被调用。

不能直接手动调用该方法。

该方法可重写以释放资源、内存。

deinit

控制器销毁时(离开堆),调用该方法。

当屏幕旋转,view 的 bounds 改变,其内部的子控件也需要按照约束调整为新的位置,因此也调用了 viewWillLayoutSubviews() 和 viewDidLayoutSubviews()。

当在一个控制器内 Present 新的控制器,原先的控制器并不会销毁,但会消失,因此调用了viewWillDisappear和viewDidDisappear方法。

如果新的控制器 Dismiss,即清除自己,原先的控制器会再一次出现,因此调用了其中的viewWillAppear和viewDidAppear方法。

若 loadView() 没有加载 view,viewDidLoad() 会一直调用 loadView() 加载 view,因此构成了死循环,程序即卡死。

一、创建

1.alloc                                  创建对象,分配空间

2.init (initWithNibName) 初始化对象,初始化数据

3.loadView                          从nib载入视图 ,通常这一步不需要去干涉。除非你没有使用xib文件创建视图

4.viewDidLoad                  载入完成,可以进行自定义数据以及动态创建其他控件

5.viewWillAppear              视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了

6.viewDidAppear              视图已在屏幕上渲染完成

loadView方法

作用:loadView方法是用来负责创建UIViewController的view。首先判断下有没有指定storyboard或者xib,如果指定,就会加载它们描述的控制器的view,如果没有指定,创建一个空的view。

什么时候调用:每次访问UIViewController的view,当view为nil,就会调用loadView方法。

ViewController *vc = [[ViewController alloc]init];

底层也会调用-(instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil方法。

(1).判断下有没有指定nibName,如果指定了,就会去加载指定的xib

(2).如果没有指定,就会判断下有没有跟控制器类名同名的xib,有,就会去加载

(3).判断下有没有跟控制器类名同名的xib,但是后缀不带Controller的xib,如果有,就会去加载

(4).如果没有任何xib描述控制器的view,就不会加载xib。会创建一个颜色为clearColor的view。

控制器的view是延迟加载的:创建控制器并不一定会创建控制器的view,等用到时再加载

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {

// Override point for customization after application launch.

self.window = [[UIWindowalloc] initWithFrame:[UIScreenmainScreen].bounds];

// 创建控制器,并一定会创建控制器的viewViewController *vc = [[ViewController alloc] init]; vc.view.backgroundColor = [UIColor redColor];

self.window.rootViewController = vc;

 [self.window makeKeyAndVisible];

returnYES;

}```

import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

// 自定义控制器的view

(void)loadView

{

NSLog(@"%s",func);

UIView *view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];

view.backgroundColor = [UIColor greenColor];

self.view = view;

}

// 控制器的view加载完成的时候调用

(void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

self.view.backgroundColor = [UIColor blueColor];

NSLog(@"%s",func);

}```

此时打印我们发现控制器的view颜色是红色的,这是因为view的get方法底层中实现了loadView 和 viewDidLoad方法,loadView中将view设置为绿色,viewDidLoad方法中又将view设置成蓝色,但是最后被vc.view.backgroundColor = [UIColor redColor];设置为红色。

- loadView

此时,控制器的 view 还未初始化,可以通过重写这个方法自定义控制器的 View,如果这样做,那就不能调用[super loadView]

- viewDidLoad

在控制器的生命周期中,它只会被调用一次,此时,view 已经初始化好,非常适合做一些页面的初始化任务。由于此时 view 的 bounds 尚未确定,所以不适合写 frame 类型的布局代码,但是给视图添加约束没有影响。

- viewWillAppear

它会在控制器的视图将要出现在屏幕中时被调用,在控制器生命周期中可能会被调用多次。在此处,适合做一些与视图出现相关联的任务,例如改变状态栏的方向、风格。

- viewWillLayoutSubviews

当 view 的子视图即将布局时,此方法会被调用,触发的条件是:

view 被添加到视图层次中

view 的 bounds 发生了改变

调用了- setNeedsLayout方法

调用了- layoutIfNeeded方法

这个方法是写 frame 布局代码的好地方,将 view 的子视图布局好,每次 view 大小发生改变时,其子视图布局也会相应改变。

- viewDidLayoutSubviews

当 view 的子视图已经布局时,此方法会被调用,触发条件同上。

- viewDidAppear

它会在控制器的视图出现在屏幕后被调用,此时,view 的 bounds 已经确定,不过在这里写布局相关代码,可能会反映到屏幕上。

- viewWillDisappear

视图即将从屏幕中消失时触发。

- viewDidDisppear

视图从屏幕中消失后触发。

/ 类的初始化方法

+ (void)initialize;

// 对象初始化方法

- (instancetype)init;

// 从归档初始化

- (instancetype)initWithCoder:(NSCoder *)coder;

// Xib初始化后

-(void)awakeFromNib;

推荐阅读更多精彩内容