本文整理自:
http://blog.csdn.net/dwt1220/article/details/29373817
http://blog.csdn.net/tiger119/article/details/8133110
一、iOS应用程序启动的三种做法
本人初学iOS,今天简单整理一下iOS应用程序启动过程。
据我现在所知iOS应用程序启动主要有三种做法:
基于
xib,
基于storyboard, 和
全手动的做法。
1、 基于xib的window base方式
第1步:将创建的xib设置为启动frame。这个可以在 target>>summary>>main interface中设置。
这有点相当于将应用的启动入口设置为本xib。
第2步:这个启动xib的file owner一定是 UIApplication。但真正的全局AppDelegate是哪个呢?
那就需要你在xib中新建一个Object,然后把类名设置为您的真正的启动代理类:xxxx_AppDelegate
注意:这里需要将启动类绑定到 file owner的delegate。(和UI元素的绑定方法一样)。
我们再看看main函数:
int retVal = UIApplicationMain(argc, argv,nil, nil);
这里没有指定启动的代理类。我猜想最后一个参数不设置的话,就会从启动xib中的UIApplication.delegate来指定。
第3步:继然是window base,那你当然需要在启动xib中创建一个window。
创建的window与代码如何对应呢?一般我们是在 xxxx_AppDelegate中创建一个UIWindow。
然后在xib中将window与代理中的实例连接上,然后代码中就直接用了,和使用一个控件一样。
这样,程序一启动,就创建了一个UIWindow。不需要你写UIWindow的创建代码。
第4步:作为一个UI程序,应该会有界面逻辑,而界面需要包含在UIViewController中,
所以,你可以在启动xib中创建UIViewController,绘制你的界面。或者直接关联别一个nib文件。
当然,你要使用它,仍然需要在xxxx_AppDelegate中声明UIViewController中的对象viewController,然后在xib中建立连接。
注意:这种方式下,UIViewController是自动创建的,不需要你写创建的代码。
最后一步:经过上面的动作。在启动代理的启动方法didFinishLaunchingWithOptions中添加以下代码就搞定了。
[
window addSubview
:
viewController
.
view
];
[
window makeKeyAndVisible
];
按照上面这种方式,我们的启动界面没有使用 alloc来创建任何ui对象,所有ui对象都是通过xib加载时自动生成的。
需要注意的是,这种方式,需要将xib设置为 main interface。如果您的程序是iphone和ipad适应的,那可以设置两个不同的启动xib.
注:
我也见到过没有设置main interface的程序,并且在main中也没有设置AppDelegate类。我猜想,默认为使用MainWindow.xib做为启动Interface。好象书中的hello_world就是这样的。
2、全手动方式
第1步:当然,我们不能设置 main interface。我们需要看看main函数。在其中设定启动代理类。
UIApplicationMain(argc, argv,nil, NSStringFromClass([SingViewTest_AppDelegateclass]));
在这里,第4个参数我们指定了启动的AppDelegate,而不是象上面那样,通过xib来指定启动代理类。
第2步:在启动方法中,自行创建window
self.window = [[[UIWindowalloc] initWithFrame:[[UIScreenmainScreen] bounds]] autorelease];
上面的代码创建一个全屏的窗体,看看,是我们自已alloc的。
第3步:通过程序来创建 SingelView的viewControoler.
self.viewController = [[[SingViewTest_ViewControlleralloc] initWithNibName:@"SingViewTest_ViewController"bundle:nil]autorelease];
如果您的viewController想通过xib来加载(通常的方式),那就采取上面的方式。
如果您不想使用 UI 设计器,你也可以
MyViewController *vc = [[ MyViewControlleralloc] init];
当然,这种情况你需要在viewdidLoad中动态生成您的ui元素。
最后一步:将viewcontroller的ui显示出来。
self
.
window
.
rootViewController
=
self
.
viewController
;
[
self
.
windowmakeKeyAndVisible
];
3、基于storyboard的方式
是基于storyboard来启动的,还待进一步研究
4、小结
通过上面两个工程的创建,可以看出,ios提供两个启动入口的方式。
方式一:指定xib做为启动interface,这种方式下,需要自已指定启动AppDelegate。
可以通过创建 object,然后改类名,再绑定的方式。
这种方式下,可以以此为起点,将真正的启动window,启动ViewController在此处创建和连接。
对于简单的应用,我们还可以在这个启动的xib里,将启动的ui都画好。
方式二:在main中指定启动AppDelegate。
这个需要修改 main函数中 UIApplicationMain方法的最后一个参数。
这种方式下,启动的windows,viewController需要自已通过alloc来生成,后面的做法和方式一就没啥区别了。
二、UIApplication简介
UIApplication对象是应用程序的象征 ,
每一个应用都有自己的UIApplication对象,而且是单例的,
通过[UIApplication sharedApplication]可以获得这个单例对象。
UIApplication *app = [UIApplication sharedApplication];
UIApplication *app1 = [UIApplication sharedApplication];
// UIApplication *app2 = [[UIApplication alloc] init]; 会出错。
NSLog(@"%p - %p ", app, app1); // 是同一个地址
一个iOS程序启动后创建的第一个对象就是UIApplication对象,
利用UIApplication对象,能进行一些应用级别的操作
如:
UIApplication *app = [UIApplication sharedApplication];
app.applicationIconBadgeNumber = 998; // 设置应用程序图标上的数字
app.networkActivityIndicatorVisible = YES; // 设置状态栏的联网动画
// 设置状态栏的样式
// app.statusBarStyle = UIStatusBarStyleLightContent; // 与下面方法的区别在于,不可设置动画。
[app setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
// 设置状态栏是否隐藏
app.statusBarHidden = YES; // 与下面方法的区别在于,不可设置动画。
[app setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
NSURL *url = [NSURL URLWithString:@"http://ios.itcast.cn"];
[app openURL:url];
注:IOS7中 如果想利用UIApplication来管理状态栏,首先得修改Info.plist的设置
在iOS7中,默认情况下,状态栏都是由UIViewController管理的,UIViewController实现下列方法就可以轻松管理状态栏的可见性和样式
状态栏的样式
-
(
UIStatusBarStyle
)
preferredStatusBarStyle
;
状态栏的可见性
-(BOOL)prefersStatusBarHidden;
openURL
- (BOOL)openURL:(NSURL*)url;
openURL:方法的部分功能有
打电话 ,发短信,发邮件,打开一个网页资源
// 打电话
UIApplication *app = [UIApplication sharedApplication];
[app openURL:[NSURL URLWithString:@"tel://10086"]];
// 发短信
[app openURL:[NSURL URLWithString:@"sms://10086"]];
// 发邮件
[app openURL:[NSURL URLWithString:@"mailto://12345@qq.com"]];
// 打开一个网页资源
[app openURL:[NSURL URLWithString:@"http://ios.itcast.cn"]];
三、iOS程序的启动过程
四、UIApplication和UIApplicationDelegate
iOS在入口函数main函数中都需要执行了一个UIApplicationMain这个函数
int UIApplicationMain(int argc, charchar *argv[], NSString *principalClassName, NSString *delegateClassName);
argc 表示argv 携带参数的数量
argv 表示传入参数的值
principalClassName:指定应用程序类名(app的象征),该类必须是UIApplication(或子类)。如果为nil,则用UIApplication类作为默认值
delegateClassName:指定应用程序的代理类,该类必须遵守UIApplicationDelegate协议,处理的事件包括:
应用程序的生命周期事件(如程序启动和关闭),系统事件(如来电) ,内存警告
AppDelegate 主要回调方法如下:
当应用程序启动完毕的时候就会调用(系统自动调用)
-
(
BOOL
)
application
:(
UIApplication
*)
application didFinishLaunchingWithOptions
:(
NSDictionary
*)
launchOptions
{
return
YES
;
}
即将失去活动状态的时候调用(失去焦点, 不可交互)
-
(
void
)
applicationWillResignActive
:(
UIApplication
*)
application
{
}
重新获取焦点(能够和用户交互)
-
(
void
)
applicationDidBecomeActive
:(
UIApplication
*)
application
{
}
/应用程序进入后台的时候调用
一般在该方法中保存应用程序的数据, 以及状态
-
(
void
)
applicationDidEnterBackground
:(
UIApplication
*)
application
{
}
应用程序即将进入前台的时候调用
一般在该方法中恢复应用程序的数据,以及状态
-
(
void
)
applicationWillEnterForeground
:(
UIApplication
*)
application
{
}
应用程序即将被销毁的时候会调用该方法
注意:如果应用程序处于挂起状态的时候无法调用该方法
-
(
void
)
applicationWillTerminate
:(
UIApplication
*)
application
{
}
应用程序接收到内存警告的时候就会调用
一般在该方法中释放掉不需要的内存
-
(
void
)
applicationDidReceiveMemoryWarning
:(
UIApplication
*)
application
{
}
五、UIWindow
UIWindow是一种特殊的UIView,通常在一个app中只会有一个UIWindow
iOS程序启动完毕后,创建的第一个视图控件就是UIWindow,接着创建控制器的view,最后将控制器的view添加到UIWindow上,于是控制器的view就显示在屏幕上了
一个iOS程序之所以能显示到屏幕上,完全是因为它有UIWindow
也就说,没有UIWindow,就看不见任何UI界面
添加UIView到UIWindow中两种常见方式:
方式1、使用(void)addSubview:(UIView *)view; 方法
这种方式会出现未知错误,不建议使用
/* 程序启动完毕之后就会调用一次,(AppDelegate中的方法)*/
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// 创建UIWindow
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// 创建控制器
// NJViewController *vc = [[NJViewController alloc] init];
// 将控制器的view添加到UIWindow上
[self.window addSubview:vc.view];
}
方式2、直接
设置UIWindow的根控制器
建议使用下面这种方式
/* 程序启动完毕之后就会调用一次,(AppDelegate中的方法)*/
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// 创建UIWindow
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// 创建控制器
// NJViewController *vc = [[NJViewController alloc] init];
/* 设置UIWindow的根控制器(建议使用下面这种方式) */
self.window.rootViewController = vc;
}
常用方法
让UIWindow成为主窗口且让它可见
[self.window makeKeyAndVisible];
让UIWindow成为主窗口 (
key Window
)
[self.window makeKeyWindow];
UIWindow的获得
获取应用程序的主窗口
NSLog(@"%@", [UIApplication sharedApplication].keyWindow);
获得某个UIView所在的UIWindow
注:
key Window是
用来接收键盘以及非触摸类的消息事件的UIWindow,而且程序中每个时刻只能有一个UIWindow是key Window。如果某个UIWindow内部的文本框不能输入文字,可能是因为这个UIWindow不是keyWindow(特别是IOS7之前)
六、UIViewControllerd生命周期方法
当一个视图控制器被创建,并在屏幕上显示的时候。 代码的执行顺序如下:
1、 alloc 创建对象,分配空间
2、init (initWithNibName) 初始化对象,初始化数据
3、loadView 从nib载入视图 ,通常这一步不需要去干涉。除非你没有使用xib文件创建视图
4、viewDidLoad 载入完成,可以进行自定义数据以及动态创建其他控件
5、viewWillAppear 视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了
6、viewDidAppear 视图已在屏幕上渲染完成
当一个视图被移除屏幕并且销毁的时候的执行顺序,这个顺序差不多和上面的相反
1、viewWillDisappear 视图将被从屏幕上移除之前执行
2、viewDidDisappear 视图已经被从屏幕上移除,用户看不到这个视图了
3、dealloc 视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放
关于viewDidUnload :
在发生内存警告的时候如果本视图不是当前屏幕上正在显示的视图的话, didReceivedMemoryWaring->viewWillUnload->viewDidUnload将会被执行,本视图的所有子视图将被销毁,以释放内存,此时开发者需要手动对viewLoad、viewDidLoad中创建的对象释放内存。 因为当这个视图再次显示在屏幕上的时候,viewLoad、viewDidLoad 再次被调用,以便再次构造视图。
当我们创建一个UIViewController类的对象时,通常系统会生成几个默认的方法,这些方法大多与视图的调用有关,但是在视图调用时,这些方法的调用顺序如何,需要整理下。
通常上述方法包括如下几种,这些方法都是UIViewController类的方法:
- (void)viewDidLoad;
- (void)viewDidUnload;
- (void)viewWillAppear:(BOOL)animated;
- (void)viewDidAppear:(BOOL)animated;
- (void)viewWillDisappear:(BOOL)animated;
- (void)viewDidDisappear:(BOOL)animated;
下面介绍下APP在运行时的调用顺序。
1)-
loadView
此方法在控制器的view为nil的时候被调用。 此方法用于以编程的方式创建view的时候用到。loadView是使用代码生成视图的时候,当视图第一次载入的时候调用的方法。用于使用(写)代码来实现控件。用于使用代码生成控件的函数。如:
- (
void ) loadView {
UIView *view
= [ [ UIView alloc] initWithFrame:[ UIScreen
mainScreen] .applicationFrame] ;
[ view
setBackgroundColor:_color] ;
self.view = view;
[ view release] ;
}
2)- (void)viewDidLoad;
一个APP在载入时会先通过调用loadView方法或者载入IB中创建的初始界面的方法,将视图载入到内存中。然后会调用viewDidLoad方法来进行进一步的设置。通常,我们对于各种初始数据的载入,初始设定等很多内容,都会在这个方法中实现,所以这个方法是一个很常用,很重要的方法。
此方法只有当view从nib文件初始化的时候才被调用。viewDidLoad用于初始化,加载时用到的。
但是要注意,这个方法只会在APP刚开始加载的时候调用一次,以后都不会再调用它了,所以只能用来做初始设置。
3) - (void)viewDidUnload;
在内存足够的情况下,软件的视图通常会一直保存在内存中,但是如果内存不够,一些没有正在显示的viewcontroller就会收到内存不够的警告,然后就会释放自己拥有的视图,以达到释放内存的目的。但是系统只会释放内存,并不会释放对象的所有权,所以通常我们需要在这里将不需要在内存中保留的对象释放所有权,也就是将其指针置为nil。
这个方法通常并不会在视图变换的时候被调用,而只会在系统退出或者收到内存警告的时候才会被调用。但是由于我们需要保证在收到内存警告的时候能够对其作出反应,所以这个方法通常我们都需要去实现。
另外,即使在设备上按了Home键之后,系统也不一定会调用这个方法,因为IOS4之后,系统允许将APP在后台挂起,并将其继续滞留在内存中,因此,viewcontroller并不会调用这个方法来清除内存。
4)- (void)viewWillAppear:(BOOL)animated;
系统在载入所有数据后,将会在屏幕上显示视图,这时会先调用这个方法。通常我们会利用这个方法,对即将显示的视图做进一步的设置。例如,我们可以利用这个方法来设置设备不同方向时该如何显示。
另外一方面,当APP有多个视图时,在视图间切换时,并不会再次载入viewDidLoad方法,所以如果在调入视图时,需要对数据做更新,就只能在这个方法内实现了。所以这个方法也非常常用。
5) - (void)viewDidAppear:(BOOL)animated;
有时候,由于一些特殊的原因,我们不能在viewWillApper方法里,对视图进行更新。那么可以重写这个方法,在这里对正在显示的视图进行进一步的设置。
6) - (void)viewWillDisappear:(BOOL)animated;
在视图变换时,当前视图在即将被移除、或者被覆盖时,会调用这个方法进行一些善后的处理和设置。
由于在IOS4之后,系统允许将APP在后台挂起,所以在按了Home键之后,系统并不会调用这个方法,因为就这个APP本身而言,APP显示的view,仍是挂起时候的view,所以并不会调用这个方法。
7) - (void)viewDidDisappear:(BOOL)animated;
我们可以重写这个方法,对已经消失,或者被覆盖,或者已经隐藏了的视图做一些其他操作。
七、四大对象关系图
结束!