一个应用程序运行就必需要有一个进程,一个进程至少要有一个线程,咱们把这个线程叫作主线程,主线程开启以后会开启一个主运行循环,若是不开启一个运行循环,程序开启了就立刻结束了,不会一直运行。换句话来讲一个APP开启就关闭了,因此必须开启一个死循环,不断的在监听事件,用户操做....等等一些事件,说完那就来看看程序怎么启动的。ios
一个app用程序启动就必需要有且仅有一个UIApplication(或则其子类)应用管理类,UIApplication 这个类的对象是一个单例对象。在程序里可用 [UIApplication sharedApplication]来获取这个单例对象,从这句话有能看出苹果单例的命名是 shared 开头windows
--------- 单例:就是无论声明多少次只有一个对象,换句话就是只有一分内存,xcode
那么UIApplication对象什么时候建立的?
一个程序都有一个main函数,iOS也不例外在xcode里有一个main.m文件,这个main就是一个应用程序启动的入口。
这个方法会调用了 UIApplicationMain,一切奥秘都在这个方法里,咱们先看看这个方法是怎么调用的网络
/// argc 与 argv是在终端传参的时候有用
// argc: 传入的参数,默认是1,若是在终端中调用当前应用程序传入其余参数就是其余参数个数 + 1
// argv: 默认第一个参数是程序的路径,其余参数是传进来的参数
// principalClassName: 默认就是@"UIApplication"
// delegateClassName: 利用类名转字符串不容易写错 传进去一个字符串利用反射机制把字符串反射成UIApplication的代理对象
UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);app
UIApplicationMain底层实现,主要是用到了反射机制利用字符串生成类建立对象ide
上面提到一个UIApplication类,那么UIApplication对象有什么用?
UIApplication的一个主要工做是处理用户事件,它会起一个队列,把全部用户事件都放入队列,逐个处理,在处理的时候,它会发送当前事件到一个合适的处理事件的目标控件。此外,UIApplication实例还维护一个在本应用中打开的window列表(UIWindow实例),这样它就能够接触应用中的任何一个UIView对象。UIApplication实例会被赋予一个代理对象,以处理应用程序的生命周期事件,还能够作其余应用级别的任务。因此UIApplication的核心做用是提供了iOS程序运行期间的控制和协做工做。函数
1、 下面是利用UIApplication 设置一些应用的功能oop
1. 发送短信动画
[[UIApplicationsharedApplication]openURL:[NSURLURLWithString:@"sms://466453"]];
2. APP图标消息数量提醒框google
// 设置APP图标提醒数字,IOS8之后要想设置applicationIconBadgeNumber这个属性, // 必须注册一个用户通知 -[UIApplication registerUserNotificationSettings:] UIApplication *app = [UIApplication sharedApplication]; // 建立一个用户通知 UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge categories:nil]; // 注册通知 [app registerUserNotificationSettings:settings]; app.applicationIconBadgeNumber = 10;
3. 网络状态设置
app.networkActivityIndicatorVisible = YES;
- 4.控制状态栏
———————— 第一种方法 交给UIViewController控制器控制管理
- IOS7应用程序的状态栏默认是交给UIViewController控制器控制管理
- 若是要交给Application管理须要在info.plist文件增长一条属性
// 带有动画效果的隐藏 // [app setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide]; [app setStatusBarHidden:YES];
———————— 第二中方法 经过控制器去重写方法prefersStatusBarHidden方法完成隐藏状态栏
// 控制器 - 隐藏状态栏 - (BOOL)prefersStatusBarHidden { return YES; } // 控制器 - 状态栏的样式 - (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleLightContent; }
- 5.设置摇动手势的时候,是否支持redo,undo操做
[UIApplication sharedApplication].applicationSupportsShakeToEdit = YES;
- 6.判断程序运行状态
/// UIApplicationStateActive, /// UIApplicationStateInactive, /// UIApplicationStateBackground if([UIApplication sharedApplication].applicationState == UIApplicationStateInactive){ NSLog(@"程序在运行状态"); }
- 7.阻止屏幕变暗进入休眠状态 -> 尽可能别使用本功能,由于很耗电。
[UIApplication sharedApplication].idleTimerDisabled = YES;
- 8.在map上显示一个地址
NSString *addressText = @"1 Infinite Loop, Cupertino, CA 95014"; addressText = [addressTextstringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]; NSString *urlText = [NSStringstringWithFormat:@"http://maps.google.com/maps?q=%@", addressText]; [[UIApplication sharedApplication] openURL:[NSURLURLWithString:urlText]];
- 9.发送电子邮件
NSString *recipients =@"mailto:first@example.com?cc=second@example.com,third@example.com&subject=Hello from California!"; NSString *body =@"&body=It is raining in sunny California!"; NSString *email = [NSStringstringWithFormat:@"%@%@", recipients, body]; email = [emailstringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; [[UIApplication sharedApplication] openURL:[NSURLURLWithString:email]];
- 10.打电话到一个号码
[[UIApplication sharedApplication] openURL:[NSURLURLWithString:@"tel://10086"]];
- 11.打开一个网址
[[UIApplication sharedApplication] openURL:[NSURLURLWithString:@"http://www.baidu.com"]];
2、 UIApplication 与 delegate
上面介绍程序启动的时候在main函数里会调用UIApplicationMain方法传进去的后2个参数就是UIApplication 与UIApplicationDelegate 2个类的字符串,以后利用反射把UIApplication的实例对象设置为UIApplication的代理,因此在Xcode建立以后会带2个文件【AppDelegate.h】和【AppDelegate.m】这2个文件,这2个文件就是系统生成的UIApplication代理文件,里面遵照了【<UIApplicationDelegate>】这个协议,因此他能帮助UIApplication在程序启动的时候能监听不少事,好比
下面就是UIApplication代理能作的一些经常使用事件
// app程序完成后调用 1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 咱们通常在这里作一些程序启动以后须要的设置 // 或者纯代码编写的时候,对窗口的初始化,控制器的指定......... return YES; } // 当程序载入后执行 2. - (void)applicationDidFinishLaunching:(UIApplication*)application // app失去焦点的时候 3. - (void)applicationWillResignActive:(UIApplication *)application; // 返回后台调用 // app被打断的时候,在这里能够保存一些数据 4. - (void)applicationDidEnterBackground:(UIApplication *)application; // 进入前台的时候调用 5. - (void)applicationWillEnterForeground:(UIApplication *)application; // 应用程序获取到焦点的时候调用, // 换句话来讲就是回到前台能与用户交互的时候调用 6. - (void)applicationDidBecomeActive:(UIApplication *)application; // 被销毁的时候调用 // 几乎感觉这个事件的调用,由于事件过短了,因此若是程序关闭须要作些事情最好别在这里写,可能没等执行程序就关闭了 // 这个须要要设置UIApplicationExitsOnSuspend的键值 7. - (void)applicationWillTerminate:(UIApplication *)application; // 内存警告调,由于iPhone内存有限,因此内存管理很是重要,不慎重程序内存越积越多,达到必定度,程序就会闪退,崩溃,其余问题,因此请珍惜每一分内存的使用,若是内存达到必定程度,你能够利用这个函数清理内存 8. - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application; // 请求委托打开一个URL资源 // 当经过url执行 9. - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url; 10. - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation; // 当系统时间发生改变时执行 11. - (void)applicationSignificantTimeChange:(UIApplication *)application; // 设置 StatusBar 状态 // 当StatusBar框方向将要变化时执行 // 当StatusBar框将要变化时执行 12. - (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame; // 当StatusBar框方向将要变化时执行 13. - (void)application:(UIApplication *)application willChangeStatusBarOrientation:(UIInterfaceOrientation)newStatusBarOrientation duration:(NSTimeInterval)duration; // 当StatusBar框方向改变时执行 // 当StatusBar框变化完成后执行 14. - (void)application:(UIApplication *)application didChangeStatusBarFrame:(CGRect)oldStatusBarFrame; // 当StatusBar框方向变化完成后执行 15. - (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation; // 当一个应用程序成功的注册一个推送服务(APS) 发送到代理去 16. - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken; // 当一个应用程序注册一个推送服务(APS) 发送到代理中失败时执行 17. - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error; // 当一个运行着的应用程序收到一个远程的通知 发送到代理去... 18. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo; // 当一个运行着的程序接受一个本地的通知时执行 19. - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification; // 通知代理,受保护的文件当前变为不可用的 20. - (void)applicationProtectedDataWillBecomeUnavailable:(UIApplication *)application; // 通知代理,受保护的文件当前变为可用的 21. - (void)applicationProtectedDataDidBecomeAvailable:(UIApplication *)application;
上面这些代理方法,就是AppDelegate须要帮助UIApplication作的事
3、接下来讲说 UIWindow 窗口
UIWindow 一个特殊的UIView,也是继承自UIView。
ios程序启动以后第一个建立的控件就是UIWindow,以后在建立控制器的View,而后在把控制器的View加载到UIWindow上,而后显示,因此其实咱们看到的界面都是显示在UIWindow上的。
界面显示的3个重要对象
storyboard加载过程
若是在info.plist文件里声明了storyboard显示项,程序会自动将指定的storboard加载并显示箭头指向的控制器
若是没有指向,其实在大项目中不多有直接指定某个storyboard显示项的都是在程序启动的时候手动建立,也就是UIApplication的代理方法里去手动加载storyboard,显示指定控制器。下面就是模仿系统加载 storyboard 的过程
1. 初始化一个窗口
注意:
// 窗口的层级关系 (往下层级越高) UIKIT_EXTERN const UIWindowLevel UIWindowLevelNormal; UIKIT_EXTERNconst UIWindowLevel UIWindowLevelAlert; UIKIT_EXTERN const UIWindowLevel UIWindowLevelStatusBar; UIWindow *window = [[UIWindow all] initWithFrame:[UIScreen main].bounds];
2. 加载main.storyboard,而且建立指定的控制器
// 加载Mainstoryboard UIStoryboard *stotyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; // 获取storyboard箭头指向的控制器 // UIViewController *vc = [stotyboard instantiateViewControllerWithIdentifier:@"ViewController"]; // 获取Storyboard ID 为ViewController UIViewController *vc = [stotyboard instantiateInitialViewController]; // 设置根控制器 window.rootViewController = vc; // 有人会想把控制器的view直接添加到window上,那样会有不少弊端的,因此别那样弄 - 例如程序旋转的时候view不会跟着一块儿旋转
3. 把建立的控制器做为窗口的根控制器,显示窗口
// 设置application的主窗口 // 这个方法内部会把window.hidden设置为YES [window makeKeyAndVisible];
总结:
storyboard加载过程其实就3步骤
最后咱们来个总结:
程序启动首先去main.m文件去执行main方法 ———> 接着会执行UIApplicationMain的方法 ————> 【在里面会把传进的后面2个【一个UIApplication,一个是AppDelegate】参数实例,
而且设置AppDelegate 做为 UIApplication 的代理,而后启动一个主运行循环,监听事件,其余操做】