【IOS 开发学习总结-OC-62】IOS 应用的生命周期
【IOS 开发学习总结-OC-62】IOS 应用的生命周期
iOS 应用的操作模式分为前窗操作和后窗操作两种类型。每当应用程序从当前窗口切换至另一个窗口时,系统将触发相应的通知机制。通过调用App委托类的具体方法来进行相应的操作。通过重新编写这些方法的具体实现细节,我们可以调控应用程序在不同窗口下的功能行为。
IOS应用程序的状态
IOS应用程序可划分以下几种运行态;
1. 未启动或被禁用——程序未运行或受限于系统设置;
2. 非活动态(non-active):处于前台窗口但无法接收事件处理——当应用程序从一种运行态切换至另一种运行态时,在中间阶段会短暂进入此状态;
3. 活动态(active):正常运行且可接收事件——即为正常前台执行的状态;
4. 后台执行(background):程序后台运行并执行代码——大多数处于挂起等待额外执行时间的应用会短暂进入此阶段; 若应用程序请求更多执行时间,则会在此状态下保持较长的时间(注:若应用要求在启动时直接进入后台运行,则可以直接从"未启动"态跳转至后台执行态而不经过"非活动态")
5. 挂起态(suspended):程序处于休眠状态——系统自动转入此态且无任何提示信息(处在此状态下程序仍保留在内存中但不会执行任何代码; 当系统出现低内存警报时会将该挂起的应用彻底从内存中清除以便前台窗口释放更多内存)
下图为应用状态切换示意图:

通常情况下,应用程序的状态变化都会促使应用委托类(app delegate)相关的方法。
协议中定义的这些方法的作用:
在程序运行过程中,在某个特定阶段(即当应用即将退出非活跃状态时),该应用不会接收任何消息或事件
当应用程序进入活动状态执行时,则相反的情况是应用处于非活动状态。
- (void)applicatioTransitionedIntoBackground:(UIApplication *)application
说明:该事件会在应用程序被推送至后台时触发。因此,在此方法内需配置以确保后台持续运行。
该应用将在从后台切换回前台时被调用,这与前面提到的方法相反
该方法用于在应用程序退出时被调用,在Objective-C中常见于执行特定操作。它通常用于场景如:保存数据、完成退出前的清理工作等。为了确保应用能够安全地退出并完成所有必要的任务,请确保已设置好相关参数。建议设置AppDelegate ExitsOnSuspend键值以实现预期功能。
由于iPhone设备内存受限,在向应用程序分配过多内存时(虽然这可能导致系统资源耗尽),系统会在资源耗尽之前自动终止该应用的运行(通过在此处定义的方法来实现);可以通过在此处执行相应的操作来清理不必要的资源以避免这种情况发生)。
- (void) applicationTimeChangeOccurred:(UIApplication*) application
当系统时间发生变化时触发此操作
- (void) applicationDidFinishLaunching: (AppDelegate *) app
说明:当应用程序启动后执行
该方法标识表示程序已成功完成启动流程,并准备接收新任务。此操作通常在应用初始化阶段调用以确保所有必要的初始化工作已完成并准备好接收后续请求或事件处理任务。
当[ statusesBox ]即将发生变化时触发相应的应用事件。
-
(void) application:(UIApplication*) application willChangeStatusBarOrientation:(UIInterfaceOrientation) newStatusBarOrientation duration:(NSTimeInterval)duration
说明:该方法将在StatusBar框方向即将发生变化时触发。 -
布尔值:[应用实例] getUrl。
-
(void) application: (UIApplication*) application, upon changing the status bar orientation from old to new.
-
(void)app:(AppDelegate*)app when: (CGRect)oldStatusBarFrame changes.
应用程序启动过程
当应用程序启动时,在'未启动'状态下先变为'临时不可用'(仅短暂)后恢复为可用状态;或者直接从'未启动'状态过渡至后台运行状态
当应用程序启动时,启动过程中系统会创建一个进程和一个主线程,并在主线程中调用main()函数——主要负责初始化AppDelegate对象,并以实现应用程序与平台之间通信需求的方式设置相应的代理类
应用程序启动并完成在初始化阶段进行的各项准备工作后的主要工作都位于main()函数中。
应用启动到 active 状态的过程——加载应用程序进入前台

加载应用程序进入后台

如何确定应用是进入了前台还是进入了后台
在- (void)applicationDidFinishLaunching:(UIApplication*)application方法中可以检查iOS设备上的 UIApplication对象的applicationState属性。当应用处于前台时,该属性值为 UIApplicationStateInactive;而当处于后台时,其值则为 UIApplicationStateBackground.示例代码如下:appState = [UIApplication sharedApplication].applicationState;这个代码有助于判断应用程序将进入的状态。
程序入口函数——main 函数
main function serves as the primary entry point for the application, particularly in iOS applications, where its role is significantly minimized, with all main responsibilities being carried out by the UIKit framework.
#import <UIKit/UIKit.h>
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([MyAppDelegate class]));
}
}
代码解读
App Main应用程序会初始化一个App Main组件,该功能包含四个关键参数,无需修改这些基础设置,但与此同时我们需要了解整个程序的启动机制
argc表示用户传入的参数个数,并将这些信息传递给程序的主要执行部分。 argv则封装了用户传入的所有具体指令或数据项。 第三个参数决定了主应用程序类的名字,并将其指定为nil时,默认应用将使用AppDelegate的应用程序。 第四个字段则是程序内部自定义的一个代理标识符,在处理状态切换时会触发相应的事件响应机制。 这个标识符通常会在创建新Xcode项目时自动配置并生成相应的代理组件
AppDelegate启动并加载了程序主界面的XIB设计文件。然而该函数虽然完成了界面文件的加载但并未将其放置于应用程序窗口中因此需要在应用启动完成后通过Delegate机制调用application:willFinishLaunchingWithOptions方法时需确保该XIB文件被正确处理如果使用storyboard作为设计文件则该函数不仅负责加载主界面设计文件并且会在用户界面上显示于窗口中。
一个应用程序中可以有一个核心storyboard文件或有一个核心nib文件,但不能同时有两个项目存在
若应用程序在启动过程中未自动加载主要的故事包或NIB文件,则建议您在application:willFinishLaunchingWithOptions方法中预先准备好Windows展示。亦可通过项目设置界面或plist配置文件进行相应的调整。
响应中断的处理
当系统检测到一种基于警告机制的中断事件时,在这种情况下(例如,在这种情况下),系统会触发相应的响应流程。此时程序将暂时过渡至inactive状态。在此状态下(在此状态下),说话者可决定采取何种措施来应对这一中断事件。在用户做出决策之前(在用户做出决策之前),应用程序始终保持inactive状态( Applications will remain in an inactive state until the user makes a decision.)。——在用户选择之后(—after the user has made a decision),当前的应用程序能够恢复active状态以便继续执行当前任务( applications can return to an active state to continue executing the current task)或者切换至后台运行模式( applications can switch to a background execution mode)以释放资源供其他应用程序使用。
该通知不会将程序设置为激活状态。然而,在Banana状态下点击菜单项时会出现此提示信息。如果您关闭该提示信息,请尝试关闭指示器并重新启动应用即可解决问题。
按锁屏键也是一种中断行为。当您按下锁屏键时,系统会阻止所有触摸事件的发生,并将应用移动至后台区域。此时app的状态被设置为inactive状态,并被移动至后台区域。
流程如下图:

当有这些中断时,我们的app该怎么办?
我们应该在applicationWillResignActive:方法中:
终止所有定时任务及相关作业。
终止所有正在进行中的网络请求。
终止正在进行中的元数据查询操作。
暂时阻止视频流的播放。
如果是游戏应用,则暂时阻止其运行。
降低OpenGL ES的工作帧率设置。
终止执行非关键代码的任务调度队列和操作队列(处于inactive状态但支持后台处理)。
挂起所有分配给分发的任务队列以及非关键的操作队列(以便继续处理当前网络请求和其他时间紧迫的后台作业)。
当程序切换至active状态时,“applicationDidBecomeActive: 方法将执行并启动之前由applicationWillResignActive:方法完成的所有工作。” 例如,“重启计时器”、“继续分发队列”以及提升OpenGL ES的帧率。但游戏必须处于休眠状态且不得自动启动。
当设备在锁屏状态且设置了密码保护时, 所有内部文件均处于被锁定状态. 因此, 如果应用程序持有这些受保护文件的引用, 应该在applicationWillResignActive:方法中关闭相关引用, 并在随后的applicationDidBecomeActive:方法中重新激活这些文件的引用.
通话过程中调整应用的 UI
我们使用 iPhone 的时候,都会发现当我们在接听电话时(不挂断),回到应用界面时,通知栏会高度变高。如下图中上面的状态栏:

这个时候,在应用的UI未发生变化的情况下(如果是这样),应用界面会被状态栏所遮挡)。最佳方案是采用视图控制器来实现对应用程序界面的有效管理。当状态栏尺寸发生变化时(如果这种情况出现),视图控制器能够自动调节并适应其所有内部组件的需求。
如果应用程序未采用视图控制器而出现某些问题,则应主动响应状态栏变化的影响。——可通过注册$ window.addEventListener('UIApplicationDidChangeStatusBarFrameNotification', onChange)事件来实现这一目标。该事件处理函数将获取窗体高度,并据此适当调节当前界面尺寸。
知识扩展:UIDeviceOrientationDidChangeNotification和UIApplicationDidChangeStatusBarFrameNotification
进入后台
前臺應用通常會先將自己轉為inactive状態, 接着轉為 background 独具體实现了两种不同的工作模式, 系統會自動調用相應的应用委托 funcții și și a căută funcția de intrare înbackgroud.
Most applications enter into a suspended state shortly after completing the - (void) applicationDidChangeBackground:(UIApplication *)application method.
对于专指要求特定后台服务的应用(如处理音频内容)或涉及延迟响应时间的操作,可能会导致系统负载增加

转入后台要做的
在- (void)applicationIntoBackground:(UIApplication *)application方法中完成转入后台前需要的准备工作时,每个应用程序都必须完成的任务包括:首先,必须将用户的数据和状态信息进行可靠持久化存储,即在进入后台之前,确保所有未写入磁盘的文件或信息都被写入磁盘,以防程序在后台被终止;其次,必须释放所有未被占用的内存空间以优化系统资源利用率。
该应用程序切换到背景模式大约需要5秒钟的时间来完成相关操作。若超出该时间仍有未完成的任务,则您的程序将被退出并从内存中释放相关内容。若需执行长时间运行的任务,请调用beginBackgroundTaskWithExpirationHandler方法以设置后台任务执行时间和启动相关线程以处理长时间持续的任务。
无论是否开启执行后台任务的线程,在进入背景模式后该应用程序应在5秒钟内退出。
后台应用的内存使用
当一个应用被切换到后台运行时,开发人员应尽量释放其占用的内存空间。在系统内存不足的情况下,操作系统会优先终止那些长时间运行且占用大量内存资源并处于后台状态的应用程序。
当处于后台运行时,在保证效率的同时要求每个应用程序都应释放其最大的可用内存。
系统持续地维护多个应用程序得以同时处于后台运行的状态。
当出现内存不足的情况时,通常会终止那些资源消耗较低的任务以回收空间,并优先关闭占用最大内存量的应用以确保及时回收空间。
事实上,在应用程序中被使用的对象一旦不再被调用,则应当及时地删除其强引用以使编译器能够回收相关的内存资源;若希望通过缓存某些对象来提升程序性能,则可以在后台进程中执行相关操作以去除这些对象的强引用。
下面这样的对象应该尽快的去掉强引用:
- 存储的图片对象;
- 作为可以重新加载的大视频或数据文件
- 当前未被利用且易于生成的对象
在后台时,为了减少程序占用的内存,系统会自动执行如下操作释放内存。
- 系统清除Core Animation缓存空间中的数据;
- 移除任何系统引用的缓存图像文件;
- 删除系统管理数据缓存中的强键结点或不可变数据。
返回前台
流程如图所示:

应用进入前台的方法- (void)appWillEnterForeground:(UIApplication *)app应用于修复在应用退出后台的方法- (void)appDidBecomeActive:(UIApplication *)app中所完成的所有工作。
同时,在应用初始化时调用的应用启动相关操作应在- (void)appDidBecomeActive:(UIApplication *)app方法中执行。
当app处于休眠状态时,无法运行任何代码.因此由于无法处理来自休眠期间的通知.例如,在休眠期间收到的方向变化,时间调整,系统设置变更以及其他可能导致显示或状态变化的通知.无论程序返回后台还是前台,在接收这些通知时都需要确保正确处理.
应用程序终止
当程序满足以下任一条件时:
- 运行于iOS4.0以前的操作系统环境;
- 应用基于旧至iOS4.0之前的系统构建;
- 设备不具备多任务处理功能;
- 在其plist文件中包含有使用ApplicationExitsOnSuspend键配置项
当应用终止时,在其处于前台或后台进程中系统将通过代理机制自动发起请求 applicationWillTerminate: 这种机制的存在有助于确保你可以执行一些清理操作。
当前应用若处于suspended状态,在其即将终止的过程中不会调用applicationWillTerminate:方法。
一般来说, 该方法允许我们在其运行过程中存储用户数据和应用状态信息,并确保在重新开始时能够恢复先前的运动状态。
此方案允许你在适当的时候存储应用程序的状态信息。
此外,在此方案下还设置了五秒的有效期。
当超时发生时, 该方案将导致程序从内存中删除相关信息。
注意:用户可以手工关闭应用程序。
The Main Run Loop ——主运行循环
Main Run Loop 负责接收并处理用户的相关操作。当应用程序初始化时,默认会被设置为主_run_loop 对象,并负责接收并处理相关事件以及更新视图界面。通过观察 Main Run Loop 的运行情况可知,该线程位于程序的核心执行线路上,从而确保接收到来自用户的操作事件能够依次被正确捕获并按顺序执行。
Main Run Loop 处理事件的架构图:

用户通过设备触发一系列操作事件,在系统中被生成后会按照预定程序依次发送至指定端口进行处理。这些事件按照顺序排列后由Main run loop接收并执行相应的操作。其中最先接收并处理的是UIApplication对象,在此过程中它决定了如何对特定类型的操作进行响应和处理。当发生触摸相关的事件时,则会首先发送至主窗口,并由主窗口将此信息传递给对应的目标View进行进一步处理;而对于其他的非触摸事件,则会通过相应的通道发送给其他相关的应用程序组件或服务去做相应的响应和处理工作。
大部分事件都可以在你的应用中进行分发。这些包括像触控事件和远程操控事件(如线控耳机)在内的各种操作都由app中的responder objects负责处理。
在iOS应用中,绝大多数实体均可充当UIResponder对象。Responder objects 几乎无处不在,在你的应用中常见于如 UIApplication 对象。所有视图和UIView controller 都是响应器对象。大多数事件的目标均指定响应器对象。不过事件也可以传递给其他对象。例如,某个Unhandled 恭维控制器(如果有)能接收该事件;如果该UIView controller 也无法处理该事件,则会将此事件转发至其所属的UIView。
补充学习资料如下:
1. 该参考文档的内容较为单一,未能充分涵盖相关内容,因此值得参考对比学习. iOS应用程序生命周期(前后台切换,应用的各种状态)详解
2. iOS系统消息
3. iOS开发系列–通知与消息机制
