iOS -程序啓動原理和UIApplication的介紹

一.UIApplication 簡介
     
(1)UIApplication對象是應用程序的象徵,一個UIApplication對象就代表一個應用程序。
(2)每一個Application都有自己的UIApplication對象,而且是單例的,如果用試圖再去實例化一個UIApplication則會報錯:[ [ UIApplication alloc ]  init ];
(3)通過[UIApplication sharedApplication]可以獲得這個單例對象。
(4) 一個iOS程序啓動後創建的第一個對象就是UIApplication對象,且只有一個(可通過代碼獲取兩個UIApplication對象,打印地址相同)。
(5)利用UIApplication對象,能進行一些應用級別的操作。

二.應用級別的操作舉例
1)設置應用程序圖標右上角的紅色提醒數字(如QQ消息的時候,圖標上面會顯示1,2,3條新信息等。)
@property(nonatomic)NSIntegerapplicationIconBadgeNumber__TVOS_PROHIBITED
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}
//點擊屏幕會調用該方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UIApplication *app = [UIApplication sharedApplication];
    //註冊通知
    UIUserNotificationSettings *nitice = [UIUserNotificationSettings
    settingsForTypes:UIUserNotificationTypeBadge categories:nil];
    
    [app registerUserNotificationSettings:nitice];
    //IconBadgeNumber
    app.applicationIconBadgeNumber = 20;
}
@end

運行效果:


2)設置聯網指示器的可見性
@property(nonatomic,getter=isNetworkActivityIndicatorVisible)BOOLnetworkActivityIndicatorVisible__TVOS_PROHIBITED;
代碼:app.networkActivityIndicatorVisible=YES;
運行效果:


3)管理狀態欄
從iOS7開始,系統提供了2種管理狀態欄的方式
a.通過UIViewController管理(每一個UIViewController都可以擁有自己不同的狀態欄).
在iOS7中,默認情況下,狀態欄都是由UIViewController管理的,UIViewController實現下列方法就可以輕鬆管理狀態欄的可見性和樣式
狀態欄的樣式     - (UIStatusBarStyle)preferredStatusBarStyle; 
狀態欄的可見性  -(BOOL)prefersStatusBarHidden;
代碼:
#pragma mark - 狀態欄的樣式
- (UIStatusBarStyle)preferredStatusBarStyle {

    return  UIStatusBarStyleLightContent;
}
#pragma mark - 是否隱藏狀態欄(no)
- (BOOL)prefersStatusBarHidden {
    return NO;
}


b.通過UIApplication管理(一個應用程序的狀態欄都由它統一管理)
如果想利用UIApplication來管理狀態欄,首先得修改Info.plist的設置


代碼:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //獲取
    UIApplication *app = [UIApplication sharedApplication];
    //註冊通知
    UIUserNotificationSettings *nitice =
    [UIUserNotificationSettings          settingsForTypes:UIUserNotificationTypeBadge categories:nil];
    [app registerUserNotificationSettings:nitice];
    //IconBadgeNumber
    app.applicationIconBadgeNumber = 20;
    app.networkActivityIndicatorVisible = YES;
     //設置狀態欄
    app.statusBarHidden = NO;
    app.statusBarStyle = UIStatusBarStyleDefault;
}


注意:既然兩種都可以對狀態欄進行管理,那麼什麼時候該用什麼呢?
          如果狀態欄的樣式只設置一次,那就用UIApplication來進行管理;
          如果狀態欄是否隱藏,樣式不一樣那就用控制器進行管理。
 4)openURL:方法

UIApplication有個功能十分強大的openURL:方法
- (BOOL)openURL:(NSURL*)url
openURL:方法的部分功能有
打電話   
[app openURL:[NSURLURLWithString:@"tel://10010"]];
發短信 
[app openURL:[NSURLURLWithString:@"sms://10010"]];
發郵件 
[app openURL:[NSURLURLWithString:@"mailto://[email protected]"]];
打開一個網頁資源 
[appopenURL:[[NSURL alloc]initWithString:@"http://baidu.com"]];

打開其他app程序   openURL方法,可以打開其他APP。

 URL
     URL:統一資源定位符,用來唯一的表示一個資源。 
     URL格式: 協議頭://主機地址/資源路徑
     網絡資源:http/ ftp等   表示百度地址:http://baidu.com
     本地資源:file:///users/apple/desktop/abc.png(主機地址省略)

三. UIApplication Delegate

     爲什麼會UIApplication Delegate?
     移動操作系統都有個致命的缺點:app容易受到打擾。比如電話或者鎖屏會導致app進入後臺甚至被終止。此時app會產生一些系統事件,UIApplication會通知它的delegate對象,讓delegate代理來處理這些系統事件。
     總結: AppDelegate的主要作用就是處理(監聽)應用程序本身的各種事件
         應用程序啓動完畢
          應用程序進入後臺
          應用程序進入前臺
         等,應用程序自身的一些事件 
        
 要想成爲UIApplication的代理對象,必須遵守:UIApplicationDelegate協議每次創建新項目,Xcode會幫我生成一個“AppDelegate”的類,它就是代理,並且該類已經默認遵循了UIApplicationDelegate的代理,且成爲了代理(在程序啓動部分會有更多解釋)。




UIApplication的代理協議有許多,AppDelegate這個類默認遵循了<UIApplicationDelegate> ,而且實現了部分代理方法,從而監控我們的應用程序。
UIApplication的代理屬性:
@property(nullable,nonatomic,assign)id<UIApplicationDelegate> delegate;

實現的代理方法在AppDelegate.m中如下:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // 當應用程序啓動完畢的時候就會調用(系統自動調用)
    NSLog(@"%s",__func__);
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    // 即將失去活動狀態的時候調用
     NSLog(@"%s",__func__);
}

- (void)applicationDidEnterBackground:(UIApplication *)application {

    // 應用程序進入後臺的時候調用
     NSLog(@"%s",__func__);
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
          / / 應用程序即將進入前臺的時候調用
     NSLog(@"%s",__func__);
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
      // 重新激活(能夠和用戶交互)
     NSLog(@"%s",__func__);
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // 應用程序即將被銷燬的時候會調用該方法
     NSLog(@"%s",__func__);
}

應用程序一般有五個狀態:官方文檔app.states



四、程序啓動原理

1.先簡單回顧一下,我們最經典的應用程序hello world:
它告訴我們,應用程序的入口是main函數;
#include<stdio.h>
int main(int argc,char* argv[])
{
    printf("hello, world\n");
    return 0;
}

2.再看一段Linux下的qt的一個應用程序:     
它的程序入口也是main函數,且app.exec();將應用程序的控制權傳遞給Qt
,進入事件循環的狀態,等待用戶操作。

#include <QtGui>
int main(int argc,char *argv[]) {
    QApplication app(argc,argv);
    QLabel label(QString("hellow qt"));
    label.show();
    app.exec();
}

3. 由此,可以猜測iOS的程序的入口也是main函數,最終程序也會進入一個事件的循環,等待用戶操作,監控;
在iOS的main.m,找到了程序的入口main函數,該函數只有一句;
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

即:main函數中調用了UIApplicationMain方法
intUIApplicationMain(intargc,char*argv[],NSString*__nullable principalClassName, NSString * __nullable delegateClassName);
  • argcargc是命令行總的參數個數
  • argvargv[]是argh個參數,記錄用戶輸入的參數;
  • principalClassName指定應用程序類名(app的象徵),該類必須是UIApplication(或子類),如果爲nil則用UIApplication類作爲默認值
  • delegateClassName指定應用程序的代理類UIApplicationDelegate協議中定義的方法,在該類中實現
     UIApplicationMain函數會根據principalClassName創建UIApplication對象,根據delegateClassName創建一個delegate對象,並將該delegate對象賦值給UIApplication對象中的delegate屬性,接着會建立應用程序的Main Runloop(事件循環),進行事件的處理(首先會在程序完畢後調用delegate對象的application:didFinishLaunchingWithOptions:方法程序正常退出時UIApplicationMain函數才返回。
    
     總結:UIApplicationMain就是讓我們的應用程序和代理之間建立聯繫,然後進入Runloop,進行事件處理;我們直接給UIApplicationMain傳遞應用程序的類名和代理的類名也是一樣的。
即:return  UIApplicationMain(argc, argv, @"UIApplication",@"AppDelegate");

4.程序啓動的完整過程:


1.main函數
     UIApplicationMain
     * 創建UIApplication對象
     * 創建UIApplication的delegate對象
2.delegate對象開始處理(監聽)系統事件
     2.1沒有storyboard
     * 程序啓動完畢的時候, 就會調用代理的application:didFinishLaunchingWithOptions:方法
     * 在application:didFinishLaunchingWithOptions:中創建UIWindow
     * 創建和設置UIWindow的rootViewController
     * 顯示窗口
代碼:
#import "AppDelegate.h"
#import "ViewController.h"

      - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    ViewController *vc = [[ViewController alloc] init];
    self.window.rootViewController = vc;
    vc.view.backgroundColor = [UIColor redColor];
    [self.window makeKeyAndVisible];
    return YES;
}

     2.2.(有storyboard)
     根據Info.plist獲得最主要storyboard的文件名,加載最主要的storyboard
     * 創建UIWindow
     * 創建和設置UIWindow的rootViewController
     * 顯示窗口 


發佈了40 篇原創文章 · 獲贊 0 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章