iOS程序启动的完整过程和控制器与视图的生命周期详解

前言:

    这部分内容,对于大部分人来说使用起来可能已经非常熟练,但是涉及到的细节还是挺多的,对于新开发者可能不是很明白,没有一个整体的思路,此文旨在帮助入门者整理一下,顺便自己也加深一下印象,只有理解了这些过程与方法,才能更好的写代码,让我们的应用程序设计更合理。其中有些问题也是面试经常被问到的一个问题,希望能帮助到大家。谢谢。

一:UIWindow对象

         UIWindow是一种特殊的UIView, 继承自UIView。通常一个app只会有一个UIWindow对象,iOS程序启动完毕后,创建的第一个视图控件就是UIWindow,接着创建控制器和控制器的view,最后将控制器的view添加到UIWindow上,于是控制器的view就显示在屏幕上了,一个iOS程序之所以能显示到屏幕上,完全是因为它有UIWindow

二:应用程序的启动过程

创建过程UIWindow -> UIViewController -> UIView ->把UIView加到UIWindow对象中。

int main(int argc, char * argv[]) {@autoreleasepool {return UIApplicationMain(argc,argv,nil,NSStringFromClass([AppDelegateclass]));}}

             nil:设置启动UIApplication对象,

             NSStringFromClass([AppDelegate class]):设置代理对象AppDelegate。 并且将AppDelegate代理对象设置给UIApplication对象 最后创建事件循环

1.>.调用main函数。

2.>在main函数中调用UIApplicationMain函数。

3.>在UIApplicationMain()函数中:

      (1)创建UIApplication对象、AppDelegate对象

      (2)设置UIApplicatio对象的代理是AppDelegate对象。

      (3) AppDelegate对象开始监听"系统事件(应用程序的事件)",进入"事件循环"。

      (4)程序启动完毕后调用application:didFinishLaunchingWithOptions:方法。,

2.1:在应用程序的启动过程中,窗口必须有根控制器,控制器必须有视图,这样视图才能显示给用户,

控制器UIViewController的创建方式:

          2.1.1:代码创建

完成前面工作后,在此方法中:

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

//创建UIWindow对象

self.window=[[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

//创建窗口的根控制器

UIViewController *rootVC=[[UIViewController alloc] init];

//设置根控制器视图的背景颜色

rootVC.view.backgroundColor=[UIColor redColor];

//把创建的控制器作为窗口的根控制器

self.window.rootViewController=rootVC;

//让窗口显示在屏幕上

[self.window makeKeyAndVisible];

return YES;

}

注意:如果窗口没有根控制器会报错

reason: 'Application windows are expected to have a root view controller at the end of application launch'

          2.1.2:加载storyboard文件

完成前面工作后,在此方法中:

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

1://通过系统提供的Main.storyboard,此过程由系统完成

*系统自动创建UIWindow对象。

*根据Info.plist文件配置(Main Interface),找到需要加载的storyboard文件(Main.storyboard)

*找到Main.storyboard中的Is Initial View Controller对应的控制器类,创建该控制器对象,并创建该控制器对应的view。

*设置UIWindow的根控制器(rootViewController)为刚才创建的控制器。

*显示UIWindow([self.window makeKeyAndVisible])。


2://通过代码,加载自己创建的My.storyboard文件创建

//创建窗口

self.window= [[UIWindow alloc] initWithFrame:[UIScreenmainScreen].bounds];

//创建UIStoryboard对象  Name:传storyboard的文件名,不需要带后缀

UIStoryboard*storyboard = [UIStoryboard storyboardWithName:@"My"bundle:nil];

// 实例化一个控制器 

第一种:创建箭头指向的控制器、如果有勾选了iS Initial View Controller的控制器

UIViewController*vc = [storyboard instantiateInitialViewController];

第二种;创建有标示符的控制器,当storyboard文件中有多个控制器的时候使用,需要设置此控制器的Storyboard ID 为''vc'', 此方法会覆盖上面的方法。

UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"vc"];

// 设置窗口的跟控制器

self.window.rootViewController= vc;

// 让窗口显示出来并且成为主窗口

[self.windowmakeKeyAndVisible];

return YES;

视图UIView的创建方式

       视图控制器创建好之后,就会创建控制器的视图View,控制器view是懒加载的过程,也就是说,在需要的时候(在用到的时候)才会创建(调用loadView方法),在控制器view的加载过程中,系统底层会调用View的get方法,这个get方法内部会调用这个loadView和viewDidLoad的方法,只要控制器的loadView方法被调用了,当调用完毕控制器的loadView方法以后,那么证明控制器的View创建好了,当控制器的View被创建好以后,紧接着就调用控制器的viewDidLoad方法。

注意:无论控制器是如何创建的,只要在控制器中,重写了("实现了")loadView方法,并且没有调用[super loadView]方法,那么最终控制器的View就必须完全在loadView方法中自己来创建了。所以loadView方法可以用来自定义View。

1>通过storyboard创建的控制器,系统会帮我们加载对应控制器所描述的view,

2>通过Xib创建控制器的view

如果没有重写loadView方法  底层实现方式

(1)创建一个xib文件,

(2)自定义一个控制器ViewController,

(3)告诉这个xib是用来描述哪个控制器,设置文件拥有者,设置file‘s.Owner的class为ViewController,就可以连线,然后连线 右键file‘s.Owner把view连到xib文件的view上

(4)在此方法中

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

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

//通过Xib创建控制器的view  Nib:xib名称

self.window.rootViewController= [[ViewController alloc] initWithNibName:@"My"bundle:nil];

[self.windowmakeKeyAndVisible];

returnYES;

}

通过xib创建控制器view的加载顺序

      当用xib创建控制器view的时候,如果写了name名称,就加载和name相同的xib,如My.xib ,不写xib名称会默认加载和控制器同名的xib,如:ViewController.xib  如果没有和控制器同名的xib,就加载和控制器同名但是去掉Controller的xib,如:View.xib,   如果都没有找到,直接创建默认控制器的View, 默认控制器的View的颜色是几乎透明的clearcolor


3>自定义

如果在控制器中重写了loadView方法  一般在此方法中自定义view

- (void)loadView

{

// [super loadView]; 调用了[super loadView],那么依然会使用默认的方式来加载。所以自定义view不需要写。

self.view = [[UIView alloc] init];

self.view.backgroundColor = [UIColor purpleColor];

}

三:控制器和视图的生命周期

生命周期的方法及调用顺序

init:初始化

loadView: 加载view

viewDidLoad: view加载完毕

viewWillAppear: 控制器的view将要显示

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

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

viewDidAppear: 控制器的view完全显示

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

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


四:一些方法说明

LoadView:

这个方法的默认实现是这样:先寻找有关可用的nib文件的信息,根据这个信息来加载nib文件,如果没有有关nib文件的信息,默认实现会创建一个空白的UIView对象,然后让这个对象成为controller的主view。

每次访问UIViewController的view(比如controller.view、self.view)而且view为nil,loadView方法就会被调用。loadView方法是用来负责创建UIViewController的view,当需要自定义view的时候我们可以重写这个方法 但是不要实现[super loadView],要不然还是按照系统默认的方式创建,你只需要在 loadView 时创建 view,不要对它做什么自定义的,

viewDidLoad

不管你是通过xib文件还是重写loadView创建UIViewController的view,在view创建完毕后,最终都会调用viewDidLoad方法,

一般我们会在这里做界面上的初始化操作,比如往view中添加一些子视图、从数据库或者网络加载模型数据装配到子视图中

awakeFromNib

当.nib文件被加载的时候,会发送一个awakeFromNib的消息到.nib文件中的每个对象,每个对象都可以定义自己的awakeFromNib函数来响应这个消息,执行一些必要的操作。也就是说通过nib文件创建view对象时执行awakeFromNib。当一个对象从xib或者storyboard中加载完毕后,就会调用一次

initWithCoder

从文件中解析一个对象的时候就会调用这个方法,一个类在IB中创建但在xocdde中被实例化时被调用的.比如,通过IB创建一个controller的nib文件,然后在xocde中通过initWithNibName来实例化这个controller,那么这个controller的initWithCoder会被调用。

由于此部分内容细节比较多,本人也只能想到这么多,如有不正确的地方,希望大神指正一下,共同进步。谢谢。。。

   

推荐阅读更多精彩内容