这篇文章主要介绍下有关UIApplication、UIWindow以及程序的启动流程,通过这篇文章,相信你会更加理解iOS 的应用启动过程以及app应用级别的相关知识。
UIApplication的一个主要工作是处理用户事件,它会起一个队列,把所有用户事件都放入队列,逐个处理,在处理的时候,它会发送当前事件到一个合适的处理事件的目标控件。此外,UIApplication实例还维护一个在本应用中打开的window列表(UIWindow实例),这样它就可以接触应用中的任何一个UIView对象。UIApplication实例会被赋予一个代理对象UIApplicationDelegate,以处理应用程序的生命周期事件(比如程序启动和关闭)、系统事件(比如来电、记事项警告)等等。
1.UIApplication对象是应用程序的象征,一个UIApplication对象就代表一个应用程序。 2.每一个应用都有自己的UIApplication对象,而且是单例的,如果试图在程序中新建一个UIApplication对象,那么将报错提示。 3.通过[UIApplicationsharedApplication]可以获得这个单例对象. 4. 一个iOS程序启动后创建的第一个对象就是UIApplication对象,且只有一个(通过代码获取两个UIApplication对象,打印地址可以看出地址是相同的)。 5.利用UIApplication对象,能进行一些应用级别的操作.
一 、设置应用程序图标右上角的红色提醒数字(如QQ消息的时候,图标上面会显示1,2,3条新信息等。)
@property(nonatomic) NSInteger applicationIconBadgeNumber;
UIApplication *app=[UIApplication sharedApplication];
app.applicationIconBadgeNumber=123;二、设置联网指示器的可见性
@property(nonatomic,getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;
代码和效果:
UIApplication *app=[UIApplication sharedApplication];
//设置指示器的联网动画
app.networkActivityIndicatorVisible=YES;三、管理状态栏
通过UIApplication管理(一个应用程序的状态栏都由它统一管理)
如果想利用UIApplication来管理状态栏,首先得修改Info.plist的设置
View controller-based status bar appearance :NO
Status bar is initially hidden :NO
Status bar style :Opaque black style这样在Info.plist设置后状态栏是白色的,后续可以在单个VC中通过 UIApplication 随意修改状态栏状态。
四、应用界别的跳转 (openURL) 通过这个方法可以打开本机其他应用和远程连接。
URL补充:
URL:统一资源定位符,用来唯一的表示一个资源。
URL格式:协议头://主机地址/资源路径
网络资源:http/ ftp等 表示百度上一张图片的地址 http://www.baidu.com/images/20140603/abc.png
本地资源:file:///users/apple/desktop/abc.png(主机地址省略)在app受到干扰时,会产生一些系统事件,这时UIApplication会通知它的delegate对象,让delegate代理来处理这些系统事件。当应用程序启动完毕的时候就会调用(系统自动调用)。
# 当应用程序启动完毕的时候就会调用(系统自动调用)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
# 即将失去活动状态的时候调用(失去焦点, 不可交互)
- (void)applicationWillResignActive:(UIApplication *)application
# 重新获取焦点(能够和用户交互)
- (void)applicationDidBecomeActive:(UIApplication *)application
# 应用程序进入后台的时候调用
# 一般在该方法中保存应用程序的数据, 以及状态
- (void)applicationDidEnterBackground:(UIApplication *)application
# 应用程序即将进入前台的时候调用
#一般在该方法中恢复应用程序的数据,以及状态
- (void)applicationWillEnterForeground:(UIApplication *)application
# 应用程序即将被销毁的时候会调用该方法
#注意:如果应用程序处于挂起状态的时候无法调用该方法
- (void)applicationWillTerminate:(UIApplication *)application
#应用级跳转(openURL的接收)
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
// NOTE: 9.0以后使用新API接口
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
#注册通知、推送等
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
# 应用程序接收到内存警告的时候就会调用
# 一般在该方法中释放掉不需要的内存
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application那么UIWindow是如何将View显示到屏幕上的呢? 这里有三个重要的对象UIScreen,UIWindow,UIView。
这样View就显示在窗口上了
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 1.创建窗口
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
*************************** 类文件**********************************
//创建窗口的根控制器,并且赋值
UIViewController *rootVc = [[UIViewController alloc]init];
self.window.rootViewController = rootVc;
************************ main.storyboard ****************************
// 2.加载main.storyboard,创建main.storyboard描述的控制器
// UIStoryboard专门用来加载stroyboard
// name:storyboard名称不需要后缀
UIStoryboard *stroyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
// 加载sotryboard描述的控制器
// 加载箭头指向的控制器
UIViewController *vc = [stroyboard instantiateInitialViewController];
//根据绑定标识加载
//UIViewController *vc = [stroyboard instantiateViewControllerWithIdentifier:@"red"];
// 设置窗口的根控制器
self.window.rootViewController = vc;
***************************** xib ****************************
// 创建窗口的根控制器
// 通过xib创建控制器
ViewController *vc = [[ViewController alloc] initWithNibName:@"VC" bundle:nil];
self.window.rootViewController = vc;
// 3.显示窗口
[self.window makeKeyAndVisible];
return YES;
}什么是keyWindow,官方文档中是这样解释的"The key window is the one that is designated to receive keyboard and other non-touch related events. Only one window at a time may be the key window." 翻译过来就是说,keyWindow是指定的用来接收键盘以及非触摸类的消息,而且程序中每一个时刻只能有一个window是keyWindow。
四个关于window变化的通知:
UIWindowDidBecomeVisibleNotification
UIWindowDidBecomeHiddenNotification
UIWindowDidBecomeKeyNotification
UIWindowDidResignKeyNotification这四个通知对象中的object都代表当前已显示(隐藏),已变成keyWindow(非keyWindow)的window对象,其中的userInfo则是空的。于是我们可以注册这个四个消息,打印信息来观察keyWindow的变化以及window的显示,隐藏的变动。
UIWindow是有层级的,层级高的显示在最外面,当层级相同时,越靠后调用的显示在外面。
UIKIT_EXTERN const UIWindowLevel UIWindowLevelNormal; //默认,值为0
UIKIT_EXTERN const UIWindowLevel UIWindowLevelAlert; //值为2000
UIKIT_EXTERN const UIWindowLevel UIWindowLevelStatusBar ; // 值为1000所以UIWindowLevelNormal < UIWindowLevelStatusBar< UIWindowLevelAlert 并且层级是可以做加减的self.window.windowLevel = UIWindowLevelAlert+1;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.window.backgroundColor = [UIColor yellowColor];
[self.window makeKeyAndVisible];
UIWindow *normalWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
normalWindow.backgroundColor = [UIColor blueColor];
normalWindow.windowLevel = UIWindowLevelNormal;
[normalWindow makeKeyAndVisible];
CGRect windowRect = CGRectMake(50, 50, [[UIScreen mainScreen] bounds].size.width- 100, [[UIScreen mainScreen] bounds].size.height - 100);
UIWindow *alertLevelWindow = [[UIWindow alloc] initWithFrame:windowRect];
alertLevelWindow.windowLevel = UIWindowLevelAlert;
alertLevelWindow.backgroundColor = [UIColor redColor];
[alertLevelWindow makeKeyAndVisible];
UIWindow *statusLevelWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 50, 320, 20)];
statusLevelWindow.windowLevel = UIWindowLevelStatusBar;
statusLevelWindow.backgroundColor = [UIColor blackColor];
[statusLevelWindow makeKeyAndVisible];
NSLog(@"Normal window level: %f", UIWindowLevelNormal);
NSLog(@"Normal window level: %f", UIWindowLevelAlert);
NSLog(@"Normal window level: %f", UIWindowLevelStatusBar);
return YES;
}通过运行结果我们可以注意到两点:
1)我们生成的normalWindow虽然是在第一个默认的window之后调用makeKeyAndVisible,但是仍然没有显示出来。这说明当Level层级相同的时候,只有第一个设置为KeyWindow的显示出来,后面同级的再设置KeyWindow也不会显示。
2)statusLevelWindow在alertLevelWindow之后调用makeKeyAndVisible,淡仍然只是显示在alertLevelWindow的下方。这说明UIWindow在显示的时候是不管KeyWindow是谁,都是Level优先的,即Level最高的始终显示在最前面。
我们找到程序的入口main函数,来看程序的启动过程
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}这个默认的iOS程序就是从main函数开始执行的,但是在main函数中我们其实只能看到一个方法,这个方法内部是一个消息循环(相当于一个死循环),因此运行到这个方法UIApplicationMain之后程序不会自动退出,而只有当用户手动关闭程序这个循环才结束。此时我们可以根据UIApplicationMain函数了解程序启动的过程.
程序启动的完整过程
1. 创建窗口 UIWindow。
2. 加载mian.storyboard 并实例化view controller
3. 分配新视图控制器到窗口root viewcontroller,然后使窗口显在示屏幕上。
(假如没有storyboard)就不会加载storyboard,也就不会帮我们创建UIWindow,那么我们需要自己在程序启动完成的时候也就是在didFinishLaunchingWithOptions方法中创建。
1.创建窗口 UIWindow。
2. 创建并实例化view controller
3. 分配新视图控制器到窗口root viewcontroller,然后使窗口显在示屏幕上。

