创建控制器、控制器加载view过程、控制器view的生命周期、多控制器

在介绍四大对象的那篇博客中,可以基本了解到程序启动的过程:

main-->UIApplicationMain-->创建UIApplication的实例和app代理AppDelegate的实例并设置好代理--->在程序启动后,也就是启动画面显示之后, AppDelegate创建UIWindow(可以是自动创建的,也可以手动创建)

现在讨论的问题是,如何创建控制器并设置为UIWindow的根控制器,然后加载出控制器中的view并显示出来。

本文目录

  • 1.创建控制器的三种方式
  • 2.控制器的view的创建过程
  • 3.Controller的view的生命周期
  • 4.导航控制器的使用
  • 5.UITabBarController的简单使用
  • 6.TabBarController>>NavigationController>>ViewController主流框架

-1.创建控制器的三种方式

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.创建window
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// 2.通过storyboard加载控制器,并将initialViewController设置为window的根控制器
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Two" bundle:nil]; // sb加载
MKTwoViewController *twoViewController = [sb instantiateInitialViewController]; // 用sb初始化initialViewController
self.window.rootViewController = twoViewController;
// 3.设置window为主窗口并显示
[self.window makeKeyAndVisible];
注意如果想加载的不是initialViewController,而是sb文件中的其他controller,根据控制器的Storyboard ID来创建:
[storyboard instantiateViewControllerWithIdentifier:@"vmid"];

方法三:

是让整个xib文件中的控件都让controller管理,xib中没有控制器,而是设置xib的files owner为指定的控制器,控制器用initWithNib创建
// 1.创建window
self.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。

-控制器的view的创建过程

2.控制器的view的创建过程

回到顶部

控制器的负责它管理的view的创建,view到底是如何进行创建的呢,一般来说view的创建和控制器的创建方式是有关系的,控制器的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。

** 注意:修改了项目文件(比如:xxx.xib等,要先Product -> Clean, 然后把软件从模拟器中卸载, 然后再运行。)

** 控制器的loadView方法什么时候调用?
** 在需要用到控制器的view的时候才调用(当调用UIWindow对象的makeKeyAndVisible方法时,就需要显示该view了, 此时就表示用到View了。), 这个就叫做"延迟加载"。
** 比如当使用self.view.backgroundColor , 要设置控制器的view的背景色时(这时需要用到view了), 那么此时才会开始创建该控制器的view, 也就是说要调用loadView方法了。所以, 如果在loadView方法内部调用self.view.backgroundColor, 就发生死循环了。

** 可以通过调用控制器的self.isViewLoaded 方法来判断当前控制器的view是否已经加载完毕了。

** 并且当控制器的view加载完毕后, 会调用viewDidLoad方法(系统自己调用)。

-Controller的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.导航控制器的使用

4.导航控制器的使用

回到顶部

导航控制器本身和其他控制器没什么太大区别,但是导航控制器可以负责页面的条状,用来管理一组控制器,这些被管理的控制器成为它的子控制器(一定和子类的概念区别开)

** 使用步骤:
1> 创建、初始化一个导航控制器: UINavigationController.
2> 设置UIWindow的rootViewController为UINavigationController.
3> 通过调用push方法添加子控制器到UINavigationController。
** 注意:谁是最后一个push进来的,当前显示的就是哪个ViewController,在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions中

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的简单使用

5.UITabBarController的简单使用

回到顶部

基本上与navigationController的创建方式一样
添加子控件的时候可以使用
viewControllers属性或者setViewControllers:方法添加一个控制器数组
但是不能使用childViewController属性,这是一个只读的属性,下面是一个简单的使用例子:

// 1.创建self.window
self.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

-6.TabBarController>>NavigationController>>ViewController主流框架

6.TabBarController>>NavigationController>>ViewController主流框架

回到顶部

目前的大多数程序都采用了TabBarController>>NavigationController>>ViewController主流框架,window的根控制器是一个UITabBarController,其子控制器为多个UINavigationController,每个NavigationController可以segue或者modal出其他的控制器。

时间: 2024-12-24 05:04:52

创建控制器、控制器加载view过程、控制器view的生命周期、多控制器的相关文章

log4j的学习和log4j在程序中使用的加载作用过程

昨天进行代码评审的时候,大家都纠结在了日志信息应该如何输出上,其实我想大家应该一直都在使用log4j来对日志信息进行输出,但是未想应该有很大一部分人对log4j是不了解的,我遇到这个问题的时候也到网上找了一些参考资料,这些参考资料更多的是去介绍以下是怎么使用的.我们知道在使用log4j的时候我们需要将log4j对应的jar包放在lib下  然后将log4j.properties配置文件放在src下,也就是类的根目录下.我看很多的文章都是介绍在log4j.properties的配置文件中是如何配置

linux内核被加载的过程

二,linux内核被加载的过程 一,linux安装时遇到的概念解析 内核必须模块vmlinz(5M左右)不认识硬盘,原本是需要写跟loader中一样的内容,来加载非必要模块. 内核非必要的功能被编译为模块放在了/lib/modules(143M)中. 现采取的措施是 在loader加载kernel的同时 也加载initial RAM Disk ==initrd 到内存中. initrd在一般命名为/boot/initrd(14M) 其作用是挂载内存的虚拟文件系统, kernel根据该虚拟文件系统

JDBC加载的过程

jdbc加载的过程如图所示. 桥接模式请参照:设计模式:桥接模式 blog宗旨:用图说话

ViewController加载顺序与self.view

从Stroyboard和xib中加载的ViewController的不同点在于 1.从Storyboard加载的ViewController只调用initWithCoder:方法,从xib加载的ViewController调用的是先执行initWithNibName:方法,后执行init方法.如果使用initWithNibName:方法初始化,则不会执行init方法: 2.从Storyboard里加载的ViewController,不能在initWithCoder:里面写self.view,而从

xcode UIImageView创建、图片加载、 音频文件播放、 延迟调用

代码创建 /** 创建UIImageView */ UIImageView * imageView=[[UIImageView alloc]init]; /** 设置尺寸位置 */ imageView.frame=(CGRect){{50,50},{230,230}}; /** 创建图片 */ UIImage * image=[[UIImage alloc]init]; /** 获取图片 */ image=[UIImage imageNamed:@"图片名称"]; /** 把图片给容器

在Unity中创建可远程加载的.unity3d包

在一个Unity项目中,发布包本身不一定要包括所有的Asset(译为资产或组件),其它的部分可以单独发布为.unity3d,再由程序从本地/远程加载执行,这部分不在本文讨论范围.虽然Unity并没有直接提供.unity3d的导出功能,但可以通过其手册了解到一些,并打开菜单项. 翻看Unity关于AssetBundle的手册,有相关的链接: BuildPipeline.BuildAssetBundle Building AssetBundles [注意]导出.unity3d格式需要pro版本,非p

加载的过程中图片变形了? --教你自定义自动适配图片宽高比的RatioLayout

很多同行在开发中可能会遇到这样的问题,就是在加载图片的时候会出现图片变形的问题.其实这很可能就是你的图片宽高比和图片所在容器的宽高比不匹配造成的.比如说图片的宽为200,高为100.宽高比就是2,那么这时候把它放在宽高比为1或者3的控件上就会分别出现变窄和变宽的问题.只有在容器宽高比为2的时候图片才会和原始显示效果一样.怎样解决这个问题呢?这个时候就可以创建一个能够自适应图片宽高比的父容器来包裹ImageView就可以了.在使用RatioLayout的时候要注意以下几点: 1)ImageView

浏览器加载解析过程

为了搞清楚js  css到底在页面加载的哪个环节中被执行使用了,就找了一些文章看了下,感觉没有理解的很透彻,但也比之前有更近一步认识. 解析html以构建dom树 -> 构建render树 -> 布局render树 -> 绘制render树 上面这个流程是最基本的了,但实际上从文档被请求回来之后,一步步的执行,结合几个比较重要的点,我自己理解如下,若有问题,望指正: 重要点: 最重要的:渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局rend

页面加载的过程

浏览器加载和渲染html的顺序 1. IE下载的顺序是从上到下,渲染的顺序也是从上到下,下载和渲染是同时进行的. 2. 在渲染到页面的某一部分时,其上面的所有部分都已经下载完成(并不是说所有相关联的元素都已经下载完). 3. 如果遇到语义解释性的标签嵌入文件(JS脚本,CSS样式),那么此时IE的下载过程会启用单独连接进行下载. 4. 样式表在下载完成后,将和以前下载的所有样式表一起进行解析,解析完成后,将对此前所有元素(含以前已经渲染的)重新进行渲染. 5. JS.CSS中如有重定义,后定义函

jboss7 加载module过程

1. 调试类: org.jboss.as.server.Main的main方法 断点: Module.registerURLStreamHandlerFactoryModule(Module.getBootModuleLoader().loadModule(ModuleIdentifier.create("org.jboss.vfs"))); 2.程序过程如下: 2.1 初始化模块加载器(Module.getBootModuleLoader()) org.jboss.modules.L