在介绍四大对象的那篇博客中,可以基本了解到程序启动的过程:
main-->UIApplicationMain-->创建UIApplication的实例和app代理AppDelegate的实例并设置好代理--->在程序启动后,也就是启动画面显示之后, AppDelegate创建UIWindow(可以是自动创建的,也可以手动创建)
现在讨论的问题是,如何创建控制器并设置为UIWindow的根控制器,然后加载出控制器中的view并显示出来。
1.创建控制器的三种方式
1> 直接通过alloc + init的方式创建
2> 通过加载storyboard文件来创建一个控制器 3> 通过指定的xib文件来创建控制器方法一:
// 1.创建window self.window是强指针self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];// 2.创建控制器,并设置为window的根控制器MKOneViewController *oneViewController = [[MKOneViewController alloc]init];self.window.rootViewController = oneViewController;// 3.设置self.window为主窗口, 并显示[self.window makeKeyAndVisible];
方法二:
// 1.创建windowself.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];// 2.通过storyboard加载控制器,并将initialViewController设置为window的根控制器UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Two" bundle:nil]; // sb加载MKTwoViewController *twoViewController = [sb instantiateInitialViewController]; // 用sb初始化initialViewControllerself.window.rootViewController = twoViewController;// 3.设置window为主窗口并显示[self.window makeKeyAndVisible];注意如果想加载的不是initialViewController,而是sb文件中的其他controller,根据控制器的Storyboard ID来创建:[storyboard instantiateViewControllerWithIdentifier:@"vmid"];
方法三:
是让整个xib文件中的控件都让controller管理,xib中没有控制器,而是设置xib的files owner为指定的控制器,控制器用initWithNib创建// 1.创建windowself.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];// 2.使用xib加载控制器,并设置为window的根控制器MKThreeViewController *threeViewController = [[MKThreeViewController alloc]initWithNibName:@"MKThreeView" bundle:nil];self.window.rootViewController = threeViewController;// 3.设置self.window为主窗口,并显示[self.window makeKeyAndVisible];
使用xib需要注意的是:
如果创建控制器的时候, 没有明确指定xib文件(也就是使用这样的代码创建[[MKThreeViewController alloc]init]), 那么默认系统回去查找一个与控制器名字一样的(但是去掉后缀Controller,也就是MKThreeView.xib)的xib文件, 如果找了则使用这个xib中的view作为控制器的默认view(前提是已经将view连线,即使没有设置files owner也是可以的)。
如果找不到则尝试去找一个与控制器名字一模一样的xib文件(MKThreeViewController.xib), 然后使用这个xib文件中的view作为控制器默认的view。如果都找不到, 那么就创建一个透明的view(空的view)。 建议将这样的xib起名为带controller后缀的,因为它的作用就相当于一个controller,类似于sb中的一个controller。
2.控制器的view的创建过程
1. 通过storyboard创建, 创建完控制器后, 自动调用loadView方法,创建控制器的view。
** 此时自定义的控制器, 因为没有"重写"("实现")loadView方法, 所以loadView方法内部就是根据storyboard文件中的view来创建View的。 2. 通过xib文件创建, 创建完控制器后, 自动调用loadView创建控制器的view。 ** 此时自定义的控制器, 因为没有"重写"("实现")loadView方法, 所以loadView方法内部就是根据xib文件中的view来创建View的。 3. 通过重写(实现)UIViewController的loadView方法重写。(自己通过代码来创建控制器的View) *** 控制器的loadView方法就是用来自定义View的。 ** 如果要为控制器自定义View, 要写在loadView中, 不要写在viewDidLoad中。 *** 如果重写(实现)loadView方法中调用了[super loadView], 那么依然会使用默认的方式来加载。 *** 重写ViewController的loadView方法,用来自定义View,当自定义view的时候, 就不要调用[super loadView]了。 [super loadView];相当于执行了一下代码
if (是否是根据storyboard来创建的控制器) { self.view = storyboard中的控制器中的view;} else if (xib) { self.view = xib中的view;} else { self.view = 透明的一个view}
** 注意:无论是通过加载xib创建view、storyboard创建view, 最终都依赖于loadView方法来创建。这个方法确定了最终的view。
3.Controller的view的生命周期
下面是代表控制器视图的生命周期的7个方法 1. viewDidLoad 2. viewWillAppear 3. viewDidAppear 4. viewWillDisappear 5. viewDidDisappear 6. viewWillUnload 7. viewDidUnload 下面是这些方法的调用顺序图: 假设有两个控制器: 程序启动后:OneController的viewDidLoad--->OneController的viewWillAppear--->OneController的viewDidAppear 跳转到第二个界面:Two的viewDidLoad--->One的viewWillDisapear--->Two的viewWillAppear----> One的viewDidDisappear--->Two的viewDidAppear 返回第一个界面:Two的viewWillDisapear--->One的viewWillAppear----> Two的viewDidDisappear--->One的viewDidAppear (one的view不需再次创建) 再次跳到第二个界面:和第一次一样,two的view需要创建。
4.导航控制器的使用
UINavigationController *nav = [[UINavigationController alloc]init];self.window.rootViewController = nav; // 设置为window的根控制器 MKOneViewController *oneVC = [[MKOneViewController alloc]init]; [nav pushViewController:oneVC animated:YES]; // 将页面跳转到oneVC的view一般的应用程序中,如果有导航控制,会在创建导航控制器的时候指定它的初始控制器,而不是使用push的方式将初始控制器入栈push:
OneViewController *oneVC = [[OneViewController alloc]init];UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:oneVC];self.window.rootViewController = nav;NavigationController以下几个方法也比较常用:
[nav popViewControllerAnimated:YES]; // 弹出栈顶的控制器, 返回[nav popToRootViewControllerAnimated:YES]; // 依次弹出栈顶控制器,直到显示根控制器的view要想设置导航条的一些属性,需在导航控制器的子控制器中分别设置: 在每个控制器的viewDidLoad方法中设置当前控制器的navigationItem属性。 navigationItem属性的具体内容: *
title
属性 * titleView
属性 * leftBarButtonItem
属性:只能设置左上角的一个按钮 * leftBarButtonItems
属性: 可以设置左上角有多个按钮 * rightBarButtonItem
属性:只能设置右上角的一个按钮 * rightBarButtonItems
属性: 可以设置右上角有多个按钮 * backBarButtonItem
属性: 设置下一个控制器, 左上角的按钮。默认情况下,该按钮文字与上一个控制器的title文字相同。 如果使用storyboard设置导航栏和它的字控制器,需要注意的是: 导航控制器向子控制器连线的时候选择的是relationship segue:view controllers。
5.UITabBarController的简单使用
// 1.创建self.windowself.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];// 2.创建tabBarController控制器并设置它的子控制器,同时设置为window的根控制器UITabBarController *tab = [[UITabBarController alloc]init];OneViewController *one = [[OneViewController alloc]init];TwoViewController *two = [[TwoViewController alloc]init];ThreeViewController *three = [[ThreeViewController alloc]init];// [tab setViewControllers:@[one, two, three]];tab.viewControllers = @[one, two, three];self.window.rootViewController = tab;// 3.将window设置为主界面并显示[self.window makeKeyAndVisible];通过storyboard设置导航栏,是在导航栏显示的时候将所有的按钮都显示了出来,而不像针对每个子控制器设置的导航那样延迟加载。 注意连线时, 选择的是relationship segue