OS开发之旅之App的生命周期【转载】
原文链接 http://www.360doc.com/content/15/0918/14/27799428_499912639.shtml
在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函数。
图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就运转起来了。