控制器以及view的多种创建方式 控制器的生命周期方法 如何创建一个控制器 系统自动实现过程 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 1.创建window self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; // 2.加载storyboard,并且创建初始化控制器(箭头所指的控制器) UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; self.window.rootViewController = [storyboard instantiateInitialViewController]; // 3.显示窗口 [self.window makeKeyAndVisible]; return YES; } 1、直接创建 MJOneViewController *one = [[MJOneViewController alloc] init]; one.view.backgroundColor = [UIColor blueColor]; self.window.rootViewController = one; 2、控制器常见的创建方式有以下几种 通过storyboard创建 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Two" bundle:nil]; // UIViewController *vc = [storyboard instantiateInitialViewController]; MJTwoViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"pink"]; self.window.rootViewController = vc; 3、指定xib文件来创建 self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor whiteColor]; MJThreeViewController *three = [[MJThreeViewController alloc] initWithNibName:@"MJThree5345" bundle:nil]; self.window.rootViewController = three; [self.window makeKeyAndVisible]; ViewController的view的创建 /** 控制器创建好以后, 控制器所管理的View是如何创建的? 1> 控制器的View是通过调用控制器的loadView方法来创建的。这个方法是UIViewController中的一个方法。 ** 只要控制器的loadView方法被调用了, 那么证明控制器的View创建好了。 2> 当调用完毕控制器的loadView方法以后, 从这时开始, 才创建好了控制器的view 3> 当控制器的View被创建好以后, 紧接着就调用控制器的viewDidLoad方法 4> 控制器的View采用了懒加载的方式, 也就是说, 在需要的使用(在用到的时候)才会创建(调用loadView方法)。 ** 注意: 无论控制器是如何创建的, 只要在控制器中, 重写了("实现了")loadView方法, 并且没有调用[super loadView]方法, 那么最终控制器的View就必须完全在loadView方法中自己来创建了。所以loadView方法可以用来自定义View。 */ ** 控制器中的View的几种创建方式: 1. 先介绍self.view是通过loadView来加载的。 // 当第一次从self.view中获取view的时候(第一次使用self.view的时候), // 控制器会调用它自己的loadView方法先创建一个view, 并且把这个新创建的view设置给self.view, 然后我们就能够通过self.view获取控制器的view了 // 控制器的view, 是通过哪个方法创建出来的。 // 控制器的view也是通过"懒汉式"来加载的。(控制器的view也是采用懒加载模式) - (void)loadView { if (如果是直接通过alloc + init方法直接创建的控制器) { self.view = [[UIView alloc] init]; } else if (如果是通过storyboard创建的控制器) { // 加载storyboard中的控制器, 并把storyboard中的控制器设置给self.view } else if (通过xib创建的控制器) { // 加载xib中的view, 并把xib中的view设置给self.view } } - (void)loadView { [super loadView]; //如果希望完全自定义一个控制器的view, 那么就重写loadView方法, 同时一定不要调用父类的loadView方法。只要调用了父类的loadView方法, 那么就会执行默认的创建控制器的view的行为。 self.view = [[UIView alloc] init]; } 1. 通过storyboard创建, 创建完控制器后, 自动调用loadView方法,创建控制器的view。 ** 此时自定义的控制器, 因为没有"重写"("实现")loadView方法, 所以loadView方法内部就是根据storyboard文件中的view来创建View的。 2. 通过xib文件创建, 创建完控制器后, 自动调用loadView创建控制器的view。 ** 此时自定义的控制器, 因为没有"重写"("实现")loadView方法, 所以loadView方法内部就是根据storyboard文件中的view来创建View的。 ** 通过xib文件创建控制器的时候, 注意xib文件的名字 1> 如果创建控制器的时候, 通过initWithNibName指定了xib的名字, 那么就根据该xib创建view 2> 如果创建控制器的时候, 没有指定任何xib文件, 也没有相应的storyboard文件, 那么会尝试查找"与控制器名字相同的, 但是去除Controller的文件名的xib文件"。比如: 控制器叫做"CZViewController", 就会查找"CZView.xib"文件, 如果有, 则使用该xib文件创建view(无需手动指定, 系统自动查找)。 3> 如果创建控制器的时候, 没有指定任何xib文件, 也没有相应的storyboard文件, 也没有"CZView.xib", 那么会尝试查找与控制器名字完全相同的xib文件。比如: 控制器叫做"CZViewController", 就会查找"CZViewController.xib"文件, 如果有, 则使用该xib文件创建view(无需手动指定, 系统自动查找)。 ** 建议: 如果要使用某个xib文件名自动匹配的方式创建view, 建议名字与控制器相同。 3. 通过重写(实现)UIViewController的loadView方法重写。(自己通过代码来创建控制器的View) *** 控制器的loadView方法就是用来自定义View的。 ** 如果要为控制器自定义View, 要写在loadView中, 不要写在viewDidLoad中。 *** 如果重写(实现)loadView方法中调用了[super loadView], 那么依然会使用默认的方式来加载。 *** 重写ViewController的loadView方法,用来自定义View。 参考代码: // 重写控制器的loadView方法: - (void)loadView { // [super loadView]; self.view = [[UIView alloc] init]; self.view.backgroundColor = [UIColor purpleColor]; } 通过xib创建view的时候, 如果重写loadView返回的是一个透明的view,不是xib中的view - (void)loadView { [super loadView]; NSLog(@"loadView"); //self.view.backgroundColor = [UIColor blueColor]; } ** 注意:无论是通过加载xib创建view、storyboard创建view, 最终都依赖于loadView方法。 ** 注意:修改了项目文件(比如:xxx.xib等,要先Product -> Clean, 然后把软件从模拟器中卸载, 然后再运行。) ** 如果除非手动指定了xib文件名,则按照该文件来加载,否则如果没有指定任何文件名字,则按照对应的xib文件的命名规则来找对应的xib文件。 ** 控制器的loadView方法什么时候调用? ** 在需要用到控制器的view的时候才调用(当调用UIWindow对象的makeKeyAndVisible方法时,就需要显示该view了, 此时就表示用到View了。), 这个就叫做"延迟加载"。 ** 比如当使用self.view.backgroundColor , 要设置控制器的view的背景色时(这时需要用到view了), 那么此时才会开始创建该控制器的view, 也就是说要调用loadView方法了。所以, 如果在loadView方法内部调用self.view.backgroundColor, 就发生死循环了。 ** 可以通过调用控制器的self.isViewLoaded 方法来判断当前控制器的view是否已经加载完毕了。 ** 并且当控制器的view加载完毕后, 会调用viewDidLoad方法。 ** 演示控制器中的View的延迟加载效果(用到的时候才加载。)演示在loadView方法内部使用view,比如self.view.backgroundColor来设置背景色, 此时会发生死循环。 ** 在loadView方法, viewDidLoad方法中输出内容。调试看在调用UIWindow的makeKeyAndVisible方法之前,是否会调用这些方法。 ** 当需要访问view的时候, 调用loadView, 然后调用viewDidLoad方法, 然后才开始使用view。 控制器view的延迟加载 控制器的view是延迟加载的:用到时再加载 可以用isViewLoaded方法判断一个UIViewController的view是否已经被加载 控制器的view加载完毕就会调用viewDidLoad方法