对应用程序启动时所有方法的调用顺序分析
一个应用程序的启动过程要包括代理的创建,控制器的加载和控制器view的加载,这其中有很多关于生命周期的方法,每个方法都是有先后顺序的,如果调用顺序拿不准,或者某段代码写的方法不恰当,就会遇到各种奇葩问题。本文不怕麻烦的在几乎所有启动时要调用的方法里都用了 __FUNCTION__ 打印。结果还有有些地方出人意料的
如果你不是在董铂然博客园看到本文,请点击查看原文
首先回顾一下应用程序的启动过程
①.先加载Main函数
②.在Main函数里的 UIApplicationMain方法中,创建Application对象 创建Application的Delegate对象
③.创建主循环,代理对象开始监听事件
④.启动完毕会调用 didFinishLaunching方法,并在这个方法中创建UIWindow
⑤.设置UIWindow的根控制器是谁
⑥.如果有storyboard,会根据info.plist中找到应用程序的入口storyboard并加载箭头所指的控制器
⑦.显示窗口
本文考虑的时步骤③之后到步骤⑦结束时将要调用的方法
其中有AppDelegate,ViewController,MainView(控制器的View),ChildView(子控件的View)的18个方法
AppDelegate中的:
1.application:didFinishLaunchingWithOptions:
2.applicationDidBecomeActive:
ViewController中的:
3.loadView
4.viewDidLoad
5.load
6.initialize
7.viewWillAppear
8.viewWillLayoutSubviews
9.viewDidLayoutSubviews
10.viewDidAppear
MainView(控制器的View)中的:
11.initWithCoder(如果没有storyboard就会调用initWithFrame,这里两种方法视为一种)
12.awakeFromNib
13.layoutSubviews
14.drawRect
ChildView(子控件View)中的:
15.initWithCoder(如果没有storyboard就会调用initWithFrame,这里两种方法视为一种)
16.awakeFromNib
17.layoutSubviews
18.drawRect
那么问题来了,不往下看你可以把上面的十八个方法排个顺序么?
下面的图是Xcode6.3的beta2版
有时有变化也就是最后两个方法有点出入
我更倾向于Xcode 6.1 觉得更科学 下面就是对各个方法的整理
1 |
+ ( void )load;
|
1.这是应用程序启动就会调用的方法,在这个方法里写的代码最先调用(董铂然原创)
1 |
+ ( void )initialize;
|
2.这个是需要用到本类时才调用,这个方法里一般写 设置导航控制器的主题啊 之类的,如果在后面的方法设置导航栏主题就晚了!(当然在上面的方法里也能写)
1 |
- ( BOOL )application:(UIApplication *)application didFinishLaunchingWithOptions:( NSDictionary *)launchOptions;
|
3.这个方法里面会创建UIWindow,设置根控制器并展现,比如某些应用程序要加载授权页面也是在这加,也可以设置观察者,监听到通知切换根控制器
1 |
ChildView - (instancetype)initWithCoder:( NSCoder *)aDecoder;
|
4.这里反正我是万万没想到,childView的initwithcoder会在MainView的方法之前调用,父的都还没出来,就先整子控件? 有了解比较透彻的博友恳请告诉我谢谢。
1 |
MainView - (instancetype)initWithCoder:( NSCoder *)aDecoder;
|
5.就是关于应用程序的数据存储后的解档操作。
1 |
MainView - ( void )awakeFromNib;
|
6.在这个方法里设置view的背景等一系列普通操作,不要写关于frame的还不准,在使用IB的时候才会涉及到此方法的使用,当.nib文件被加载的时候,会发送一个awakeFromNib的消息到.nib文件中的每个对象,每个对象都可以定义自己的awakeFromNib函数来响应这个消息,执行一些必要的操作。
1 |
ChildView - ( void )awakeFromNib
|
7.子控件也有本方法,重写父类的方法。基本用法同上
1 |
- ( void )loadView;
|
8.创建视图的层次结构,这里需要注意,在没有创建控制器的view的情况下不能直接写 self.view 因为self.view的底层是:
if(_view == nil){
_view = [self loadView]
}
所以这么写会直接造成死循环。
如果重写这个loadView方法里面什么都不写,会显示黑屏。
如果写了[super view]还要看前面的控制器在创建时是写的initWithNibName(指定了xib名字),还是写的普通的init。 如果是后者还是黑屏。
如果不在这个方法中,init的底层是会调用initWithNibName的,如果名字是MainViewController,会先在项目中找MainView.xib 找不到会再找MainViewController.xib。
1 |
- ( void )viewDidLoad;
|
9.卧槽,这个方法是当年用的最多的方法,但是在之后的开发中就会发现越来越不靠谱,很多东西都还没加载完毕,各种取值都不准确,很少在这里面写东西了。 这里只是把视图元件加载完成,还没有开始布局不要设置关于 frame 之类的属性!有时可能会出现差20个像素点等状况。
1 |
- ( void )viewWillAppear:( BOOL )animated;
|
10.视图将要出现,这个方法用的非常多,比如如果要设置导航栏的setNavigationBarHiden:animate: 就必须要在这里写,才能完美契合,不卡跳。 还有很多比如监听屏幕旋转啦,
viewWillTransitionToSize:可能要在本方法里再调一次,或者就是新到这个界面要reloadData或是自动下拉刷新等 都是写在本方法里。
1 |
- ( void )viewWillLayoutSubviews;
|
11.视图将要布局子视图,苹果建议的设置界面布局属性的方法,这个方法和viewWillAppear里,系统的底层都是没有写任何代码的,也就是说这里面不写super 也是可以的
1 |
MainView - ( void )layoutSubviews;
|
12.在这个方法里一般设置子控件的frame,因为这里相当于是布局基本完成了,设置时取到的frame或者是self.bounds才最准,如果在awakeFromeNib里写会不准确 。还有这里要切记千万不能把super layoutSubviews忘了,可能最后都很难找到这个bug
1 |
- ( void )viewDidLayoutSubviews;
|
13.这个方法我也是玩玩没想到,控制器的view的子控件还没有布局好呢,怎么这个控制器就已经说布局全部完成了?那后边的布局就不等了? 有独到见解的也恳请你告诉我,这其中苹果的意思到底是什么。
1 |
ChildView - ( void )layoutSubviews;
|
14.控制器的子控件里的子控件的布局就在这里写了。
1 |
MainView - ( void )drawRect:(CGRect)rect;
|
15. 因为默认所有额UI控件都是画上去的,在这一步就是把所有的东西画上去,有时候需要用到Quartz2D的知识的时候都是在这个方法里话,但也是要注意别忘了写super,不然系统原本的东西就都画不上来了,这里要建议尽可能使用贝塞尔路径画图形,因为系统默认的那个上下文画法有时可能会内存泄露。drawRect方法只能在加载时调用一次,如果后面还需要调用,比如下载进度的圆弧,需要一直刷帧,就要使用setNeedsDisplay来定时多次调用本方法
1 |
ChildView - ( void )drawRect:(CGRect)rect;
|
16.view的子控件内部的画图方法,有时可以自己自定义label 中间带个删除线的(用来写打折前的原价) 就是在这里画根线 。
1 |
- ( void )viewDidAppear:( BOOL )animated;
|
17.把上面的画图都画完了,这里就会显示,视图完全加载完成。在这里的操作可能就是设置页面的一些动画,或者是设置tableView,collectionView,QQ聊天页面啥的滚动到底部scrollToIndexPath之类的代码操作。
1 |
- ( void )applicationDidBecomeActive:(UIApplication *)application;
|
18.最后这是AppDelegate的应用程序获取焦点方法,真正到了这里,才是所有东西全部加载完毕,应用程序整装待发保持最佳状态等待用户操作。这个方法中一般会写关于弹出键盘的方法,比如有的用户登录界面为了更好的用户体验,就让你在刚打开程序来到登录界面的时候,光标的焦点就自动在账号的文本框里闪烁,也就是设置账号文本框为第一响应者。键盘在页面加载完毕后从下方弹出,这种代码一般就在本方法写。
转载于:https://www.cnblogs.com/yangmingyu/p/6904360.html
对应用程序启动时所有方法的调用顺序分析相关推荐
- WinForm程序启动时不显示主窗体的实现方法
望程序启动时不显示主窗体,而只是在SystemTray显示一个图标:当用户点击该图标时,才第一次显示出主窗体来. 作者在文章中已经说得很清楚,将Form的Visible属性设置为false是不行的,因 ...
- 程序启动时,vc2015设置哪个窗体先打开,优先启动,设置方法
程序启动时,vc2015设置哪个窗体先打开,设置方法 工程名对应的APP文件中 InitInstance中 //Caccess_mdb_operationDlg dlg; //可以设置这里,首先启动 ...
- 如何在ASP.NET Core程序启动时运行异步任务(3)
原文:Running async tasks on app startup in ASP.NET Core (Part 3) 作者:Andrew Lock 译者:Lamond Lu 之前我写了两篇有关 ...
- 如何在ASP.NET Core程序启动时运行异步任务(2)
原文:Running async tasks on app startup in ASP.NET Core (Part 2) 作者:Andrew Lock 译者:Lamond Lu 在我的上一篇博客中 ...
- 如何在ASP.NET Core程序启动时运行异步任务(1)
原文:Running async tasks on app startup in ASP.NET Core (Part 1) 作者:Andrew Lock 译者:Lamond Lu 背景 当我们做项目 ...
- Android 解决程序启动时的黑屏问题
关于黑屏默认的情况下,程序启动时,会有一个黑屏的时期,原因是,首个activity会加载一些数据,比如初始化列表数据.向服务器发送请求获取数据等等. 去除方法: 1.在style里面添加一个style ...
- 程序启动时的黑屏问题
默认的情况下,程序启动时,会有一个黑屏的时期,原因是,首个activity会加载一些数据,比如初始化列表数据.向服务器发送请求获取数据等等.去除方法 1.在style里面添加一个style: < ...
- 2.实验室打卡精灵2.0-单实例化、开机启动、托盘操作、程序启动时隐藏主窗口
老规矩,上一张图片 最近对实验室打卡精灵做了一些优化,基本上达到了最初设想的功能. 现在的功能包括: 1.自定义早上.中午.下午.晚上的打卡时间 2.软件单实例化,即如果已经运行了一次再次运行会弹出& ...
- linux c 启动程序吗,Linux下C程序启动时的系统调用
写程序跟踪发现,在Linux i386中,一个程序体完全为空的C语言程序启动时要进行近100个系统调用,如下所示. [ 1]syscall: 11 //execve [ 2]syscall: 45 / ...
最新文章
- 搞懂限流算法这一篇就够了 No.154
- 【SSM框架系列】SpringMVC的文件上传、拦截器及异常处理
- SQL Server CheckPoint的几个误区
- mysql中uuid的写法_MySQL IS_UUID()用法及代码示例
- HTML input type 输入类型
- 奔图内部扫描错误13_现代浏览器内部揭秘(第三部分)
- Python之简单验证码实现
- java ssdb 操作link遍历map的两种方式
- 错误:document.getElementById(userForm).submit();Object is not a function
- 二级高级应用计算机考试环境,1.2 上机考试环境免费阅读_全国计算机等级考试无纸化真考题库二级MS Office高级应用免费全文_百度阅读...
- Rosie's Frankly Speaking
- 调试 STM32F429 + USB3300
- 一文带你全方位了解网卡
- 国内访问英文版维基百科地址
- 【processing】追
- 第二章:Java面向对象:抽象(abstract)类、模板方法设计模式、接口(interface)、关键字-implements(实现)、代理模式
- 计蒜客——恋爱纪念日(学习如何格式化打印日期)
- 前后端交互必备之js数组方法大全
- J-link无法下载固件问题
- 操作系统第一章 --导论