iOS開發之旅之App的生命周期 – iPhone手機開發技術文章 iPhone軟體開發教學課程

在iOS App中,入口函數並不在根目錄下,而是在“Supporting Files”目錄的main.m文件的main函數中。這很容易理解,C/C++都是以main為入口。

 

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

這個函數比較簡單,隻是調用瞭UIApplicationMain方法來啟動整個應用程序,前兩個參數就是普通C/C++的命令行參數,這裡我們可以忽略。主要看後面兩個參數。後兩個參數分別表示程序的主要類(principal class)和app代理類(delegate class)。如果主要類(principal class)為nil,將從Info.plist中獲取,如果Info.plist中不存在對應的key,則默認為UIApplication;App代理類(delegate class)將在新建工程時創建,即AppDelegate,應用程序的整個生命周期都由它來代理。

APP生命周期

根據UIApplicationMain函數,程序將進入AppDelegate.m,這個文件是xcode新建工程時自動生成的。下面看一下AppDelegate.m文件,這個關乎著應用程序的生命周期。

 

#import AppDelegate.h
@interface AppDelegate ()
@end

@implementation AppDelegate
// 應用程序第一次啟動時執行該函數,如果是手寫代碼設置應用程序window的rootViewController那麼則需要在這裡實現。該函數的功能等同於Android中的onCreate函數。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    return YES;
}
// 應用程序由激活狀態切換到未激活狀態要執行的函數,例如用戶按home鍵返回主屏幕等。類似於Android中的onPause回調函數
- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
// 應用程序已進入後臺程序時的回調函數,類似於Android中的onStop
- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
// 應用程序從未激活狀態進入到激活狀態要執行的回調函數,過程與WillResignActive相反,等同於Android中的onRestart函數。
- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
// 應用程序被激活的回調,與didEnterBackground過程想對應。onResume
- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
// 應用程序即將終止的回調函數
- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

 

 

  • application:willFinishLaunchingWithOptions:—這方法在應用第一次啟動時執行,即隻執行一次。類似於Android中的onCreate函數。

  • application:didFinishLaunchingWithOptions:—這個函數允許你在應用顯示在用戶面前之前進行最後的初始化工作。

  • applicationDidBecomeActive:—在應用程序成為前臺程序時要執行的回調函數,類似於Android中的onResume函數。

  • applicationWillResignActive:—在應用程序從前臺轉換到後臺程序時會調用的函數,類似於Android中的onStop函數。

  • applicationDidEnterBackground:—應用程序進入到後臺狀態的回調函數,此時的應用程序可能在任何時刻被掛起。

  • applicationWillEnterForeground:—應用程序從後臺進入到前臺的回調函數,但此時應用程序還不是激活狀態,類似於Android中的onRestart函數。

  • applicationWillTerminate:—應用程序將要被終止時的回調函數,如果你的程序隻是被掛起,那麼不會回調該函數,類似於Android中的onDestory函數。

 

width=305 /

圖1 圖2

如上圖1所示,應用程序啟動UIApplication,此時主線程( UI線程 )的事件循環就會開啟。並且會將App的生命周期代理給AppDelegate,首先會調用

(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions ,我們又會在該函數中設置AppDelegate中window的rootViewController為我們的第一個頁面(更多的情況是系統自動加載應用程序的默認的storyboard界面),我們會在自己的ViewController中設計UI,因此應用程序window中就加載瞭我們的UI,此時應用程序就從最初的not running狀態到瞭Active狀態。

 

UI的線程安全

在上文中我們提到瞭應用程序啟動時會啟動一個消息循環,並且這個消息循環是在主線程中的。開發過Android應用程序的同學都知道,更新UI必須在主線程中,這是因為UI控件並不是線程安全的,在Android中UI控件都是ThreadLocal的,這個ThreadLocal就是就是主線程的ThreadLocal,可以簡單的理解為UI控件的操作隻能在主線程中執行才是安全的,如果在其他線程中操作就會拋出異常,這就是UI控件的非線程安全性。

iOS中的UI控件也不是線程安全的。因為App中UI更新頻率時是很高的,如果UI是線程安全的,也就是UI控件在子線程中可以修改、更新等,那麼系統必須要對各種UI操作進行鎖操作,加鎖、解鎖、系統調度等會消耗大量的CPU資源,這樣就會導致效率底下,而且容易導致死鎖問題。因此,UI操作隻能在主線程中。官方解釋如下 :

Threading ConsiderationsManipulations to your application’s user interface must occur on the main thread. Thus, you should always call the methods of the UIView class from code running in the main thread of your application. The only time this may not be strictly necessary is when creating the view object itself but all other manipulations should occur on the main thread.

 

UIWindow與UIView

UIWindow就是應用程序窗口,簡單理解就是整個手機屏幕。UIWindow的主要功能就是提供一個區域來顯示UI視圖和將事件分發給視圖。在應用加載時,我們會設置或者由系統從plist文件中加載UIWindow的rootViewController,在UIViewController中又包含瞭各種UI控件,當應用啟動時,啟動瞭消息循環,回調App的生命周期函數,將UI控件繪制到UIWindow中,然後又通過UIWindow將用戶的各種操作通過事件的形式分發給UI控件,至此整個App就運轉起來瞭。

 

 

 

發佈留言