IOS应用程序生命周期详解
第一、 IOS应用程序的五种状态:
1. Not running:应用还没有启动,或者应用正在运行但是途中被系统停止。
2. Inactive:当前应用正在前台运行,但是并不接收事件(当前或许正在执行其它代码)。一般每当应用要从一个状态切换到另一个不同的状态时,中途过渡会短暂停留在此状态。唯一在此状态停留时间比较长的情况是:当用户锁屏时,或者系统提示用户去响应某些(诸如电话来电、有未读短信等)事件的时候。
3. Active:当前应用正在前台运行,并且接收事件。这是应用正在前台运行时所处的正常状态。
4. Background:应用处在后台,并且还在执行代码。大多数将要进入Suspended状态的应用,会先短暂进入此状态。然而,对于请求需要额外的执行时间的应用,会在此状态保持更长一段时间。另外,如果一个应用要求启动时直接进入后台运行,这样的应用会直接从Not running状态进入Background状态,中途不会经过Inactive状态。比如没有界面的应用。注此处并不特指没有界面的应用,其实也可以是有界面的应用,只是如果要直接进入background状态的话,该应用界面不会被显示。
5. Suspended:应用处在后台,并且已停止执行代码。系统自动的将应用移入此状态,且在此举之前不会对应用做任何通知。当处在此状态时,应用依然驻留内存但不执行任何程序代码。当系统发生低内存告警时,系统将会将处于Suspended状态的应用清除出内存以为正在前台运行的应用提供足够的内存。
一些低版本程序和不会在后台执行的程序不会进入background和suspend,直接从active终止。
在生命周期中会发生如下的状态转换:
第二、状态转换方法
上述状态转换流程的实现,在IOS中是通过UIApplicationDelegate代理来实现的,状态切换的回调函数如下所示:
1、- (void)applicationWillResignActive:(UIApplication *)application
说明:当应用程序将要入非活动状态执行,在此期间,应用程序不接收消息或事件,比如来电话了
2、- (void)applicationDidBecomeActive:(UIApplication *)application
说明:当应用程序入活动状态执行,这个刚好跟上面那个方法相反
3、- (void)applicationDidEnterBackground:(UIApplication *)application
说明:当程序被推送到后台的时候调用。所以要设置后台继续运行,则在这个函数里面设置即可
4、- (void)applicationWillEnterForeground:(UIApplication *)application
说明:当程序从后台将要重新回到前台时候调用,这个刚好跟上面的那个方法相反。
5、- (void)applicationWillTerminate:(UIApplication *)application
说明:当程序将要退出是被调用,通常是用来保存数据和一些退出前的清理工作。这个需要要设置UIApplicationExitsOnSuspend的键值。
6、- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
说明:iPhone设备只有有限的内存,如果为应用程序分配了太多内存操作系统会终止应用程序的运行,在终止前会执行这个方法,通常可以在这里进行内存清理工作防止程序被终止
7、- (void)applicationSignificantTimeChange:(UIApplication*)application
说明:当系统时间发生改变时执行
8、- (void)applicationDidFinishLaunching:(UIApplication*)application
说明:当程序载入后执行
9、- (void)application:(UIApplication)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
说明:当StatusBar框将要变化时执行
10、- (void)application:(UIApplication*)application willChangeStatusBarOrientation:
(UIInterfaceOrientation)newStatusBarOrientation
duration:(NSTimeInterval)duration
说明:当StatusBar框方向将要变化时执行
11、- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url
说明:当通过url执行
12、- (void)application:(UIApplication*)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation
说明:当StatusBar框方向变化完成后执行
13、- (void)application:(UIApplication*)application didChangeSetStatusBarFrame:(CGRect)oldStatusBarFrame
说明:当StatusBar框变化完成后执行
三、 iOS应用状态切换:
1. 应用启动周期
当应用启动时,将从Not running状态进入foreground或者直接进入background运行。进入前台时,其实最终是要进到Active状态,中途会先短暂进入到Inactive状态。在应用启动时,系统会创建一个process和一个主thread,并且在主thread中调用main函数,即上面二提到的。 main函数在创建工程时由Xcode自动生成。main函数负责UIApplication对象初始化,及设置UIApplication代理类等等。在应用初始化并准备进到前台运行之前的大部分工作都在main函数中完成。
应用被启动直到前台运行的过程如下图,右侧部分为调用的UIApplication代理类的方法。
iPhone中的应用程序很容易受到打扰,比如一个来电可能导致应用程序失去焦点,如果这个时候接听了电话,那么应用程序会转到后台运行。还有很多 其它类似的事件会导致iPhone应用程序失去焦点,在应用程序失去焦点前会调用委托类的applicationWillResignActive()方 法,而应用程序再次获取到焦点的时候会调用applicationDidBecomeActive()方法。比如在运行应用程序的时候锁屏会调用委托类的 applicationWillResignActive()方法,而当屏幕被解锁的时候,又会调用 applicationDidBecomeActive()方法。
另外一个非常重要的方法就是applicationDidReceiveMemoryWarning(),因为iPhone设备只有有限的内存,如 果为应用程序分配了太多内存操作系统会终止应用程序的运行,但在终止之前操作系统会通过先调用委托类的 applicationDidReceiveMemoryWarning()方法警告应用程序,在UIApplication接收到这个事件后它会传递给 委托类的applicationDidReceiveMemoryWarning()方法,委托类在这个方法内可以进行释放内存的操作以防止操作系统强制 终止应用程序的运行。
2. 响应中断
当一个基于警告的中断(诸如电话来电)发生时,应用会暂时从active状态切换到Inactive状态,以给系统提供机会提示用户,让用户决定如何处理。在用户决定如何处理此中断警告之前,应用将一直处于Inactive状态。 在用户做出选择后,当前应用或者回到active状态继续运行,或者直接切换到background状态以让位于其它的应用运行。此种情况下,应用执行流程如下图所示:
对于基于警告的中断将会导致用户暂时对应用失去控制。当前应用继续在前台foreground运行,但是不再接收任何触控事件。(事实上,应用只是不再接收触控类事件,其它类型的事件比如accelerometer事件,和通知Notification,应用仍然接收。)所以为了响应这些变化,应用需要在applicationWillResignActive:方法中做以下工作:
(1)停止timers及终止其它周期性任务。
(2)停止任何正在运行的元数据查询。
(3)不再初始化任何新任务。
(4)暂停电影播放(在AirPlay上的播放除外)
(5)游戏进入暂停状态。
(6)恢复OpenGL ES帧率。
(7)暂停任何正在临界区执行的分发队列或操作队列。(当然,当应用处于inactive状态时,应用仍然可以继续处理网络请求以及其它一些对时间敏感的后台任务)
3. 切向后台background状态
当用户按下"Home"键或者系统启动另外一个应用时,前台foreground应用首先切换到Inactive状态,然后切换到Background状态。此转换将会导致先后调用应用代理的 applicationWillResignActive:和 applicationDidEnterBackground:方法。在 applicationDidEnterBackground:方法返回后,大部分应用在之后不久转入suspended状态。对于请求特定后台background任务的应用,比如播放音乐应用,或者那些请求需要额外执行时间的应用,可能会继续执行更长一段时间
注:应用从froeground切换到background只有在支持多任务并且运行iOS4.0或更新版本系统的设备上才会发生。所有其它的情况,应用不是切向后台,而是直接终止,并且从内存中清除。
应用切向后台background时应该做什么:
应用可以在applicationDidEnterBackground:方法中做些切向background状态前需要做的一些准备工作,当切向background状态时,所有的应用需要做以下事情:
(1)应用界面快照。当applicationDidEnterBackground:方法返回时,系统保存应用界面的快照,并且使用快照图片作为转换动画。如果在你的应用界面中有涉及到敏感信息的视图,则你应该在applicationDidEnterBackground:方法返回前隐藏或者修改这些视图。
(2)保存用户数据和应用状态信息。所有没有保存的改变都应该在切向background状态前写入磁盘以保存。这一步是必须的,因为你的应用在后台时很有可能因为多种其它原因而被很快kill掉。根据需要你可以在background thread后台线程中执行这些操作。
(3)释放尽可能多的内存资源。
applicationDidEnterBackground:方法允许最多有5秒的时间去完成任何任务然后返回。实际中,此方法应该尽可能快的返回。如果在时间到期之后,此方法没有返回,则应用即被kill掉,并且清除所占用的内存。如果你的应用确实需要更多的时间去执行任务,可以调用beginBackgroundTaskWithExpirationHandler:方法请求后台执行时间,然后启动一个能长期执行任务的线程。无论你是否启动一个执行后台任务的线程,applicationDidEnterBackground:方法都必须在5秒后退出。
后台应用的内存使用:
当应用切入background时,每个应用应该释放尽可能多的实际占用的内存。系统尽量尝试在内存中同时保持尽量多的应用,但是当内存即将耗尽时,系统会终止那些挂起suspended的应用以回收内存。然而那些消耗很大数量的内存同时又处于后台background运行的应用会优先被终止。
实事求是的讲,就是当你的应用在不再需要的时候要尽快的移除对那些用过对象的引用。移除引用允许自动引用计数系统去释放对象并且回收内存。然而,如果应用为了改进性能而使用了缓存,则应用应该在切换至后台状态前等待并且释放这些缓存。下面是一些需要回收的对象的例子:
(1)缓存的图像对象
(2)比较大的多媒体文件或数据文件,这些文件可以从磁盘重新装载。
(3)任何应用当前不再需要的对象,并且这些对象后面又可以很容易重新创建。
为了帮助您的应用程序,减少其内存占用,系统会自动释放出许多幕后用于支持您的应用程序的对象。例如:
(1)释放所有的核心动画层的后备存储,以避免这些层继续在屏幕上显示,同时又不改变当前层的属性。并且并不释放层对象自已。
(2)移除所有对缓存图像的引用。(如果应用没有对这些图像强引用,则他们随后即被移除内存)
(3)释放一些系统管理的其它的数据缓存。
4. 返回前台foreground
如果应用曾被移入后台,相应的任务被停止,则此时返回前台时可以重启任务继续执行。应用的applicationWillEnterForeground:方法应该恢复所有在applicationDidEnterBackground:方法所做的工作。同时,applicationDidBecomeActive:方法应该继续执行在应用启动时所做的同样的激活任务的操作。应用从后台切入前台的程序流程如下图所示:
5.应用终止
如果应用将被终止时正在前台或后台运行,系统将会调用应用代理的applicationWillTerminate:方法以使应用能做退出前的任何需要的回收处理。你可以使用此方法保存用户数据或应用状态信息,以供应用随后重新启动恢复状态时使用。该方法最长运行时限为5秒,过期应用即被kill掉并且移除内存。
注:应用当前被suspended时,不会调用 applicationWillTerminate:方法。
即使是使用iOS SDK4或更新的版本SDK开发应用,也应该考虑应用在没有任何通知时被kill掉的情况。用户可以使用多任务UI很明确的kill掉某个应用。除此之外,如果发生内存告警,系统也会从内存中移除应用以释放空间。处于suspended状态的应用被终止时不会有任何通知。但是如果应用当前正在后台background运行,则当应用要被终止时,系统会调用应用代理的applicationWillTerminate:方法。应用不可以在此方法中申请额外的后台执行时间。
6.主运行循环main run loop
应用主运行循环负责处理所有用户相关的事件。UIApplication对象在应用启动时安装主运行循环并且使用此循环去处理事件和处理基于视图的界面更新。正如名字所表明的,该主运行循环是在应用的主线程app's main thread中运行的。以此保证所有用户事件是按照它们被接收时的顺序串行的执行。
下图展示了主运行循环的结构以及用户事件如何导致了应用行为。当用户和应用交互时,和这些交互相关的事件由系统自动产生并且借助UIKit设定的特殊端口传递给应用。事件在应用内部以队列的形式存在并且一个一个的被分发到应用的主运行循环去执行。UIApplication对象是第一个接收事件的对象,并且决定需要如何处理事件。触控事件通常被分发到应用的主窗口对象,并且最终分发到发生该触控事件的视图上面。其它的事件传递也许会经过各种各样的应用对象而与触控事件传递稍微有所不同。
参考地址:http://linwwwei.iteye.com/blog/1434360