一個應用程序運行就必需要有一個進程,一個進程至少要有一個線程,咱們把這個線程叫作主線程,主線程開啓以後會開啓一個主運行循環,若是不開啓一個運行循環,程序開啓了就立刻結束了,不會一直運行。換句話來講一個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 的代理,而後啓動一個主運行循環,監聽事件,其餘操做】