前言:
这部分内容,对于大部分人来说使用起来可能已经非常熟练,但是涉及到的细节还是挺多的,对于新开发者可能不是很明白,没有一个整体的思路,此文旨在帮助入门者整理一下,顺便自己也加深一下印象,只有理解了这些过程与方法,才能更好的写代码,让我们的应用程序设计更合理。其中有些问题也是面试经常被问到的一个问题,希望能帮助到大家。谢谢。
一: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会被调用。
由于此部分内容细节比较多,本人也只能想到这么多,如有不正确的地方,希望大神指正一下,共同进步。谢谢。。。