NS for iOS Devs —应用程序生命周期

在Swift Post上以更好的格式阅读此文章。

每个iOS开发人员都需要了解iOS应用程序的可能状态。 知道该应用何时终止或处于不活动状态,使我们知道在幕后能做什么,哪些可能行不通。 应用程序在某些情况下(例如处理切换,应用程序间通信等)需要额外的工作。

为什么我们需要知道?

首先,我们应该对应用程序的启动做出适当的响应。 某些第三方库需要在应用程序的不同状态下进行设置。 另外,我们应该准备该应用程序以使其在前台工作。 我们可能需要提供不同的用户体验。 例如,我们的应用程序在进入前台时都可能要求输入密码。 另一方面,我们的应用程序可以像Dropbox一样在后台运行时上传图像。 甚至我们可能想在应用终止后从用户离开的地方重新打开。 因此,每个功能在不同的应用程序状态下需要不同的实现。 因此,在提供不同且更好的用户体验的同时了解状态和转换可能至关重要。

我们需要知道些什么?

事不宜迟,以下是状态的简要说明:

未运行 :应用未由系统启动或终止。

后台 :应用程序在后台运行,仍然能够运行代码。 但是此状态的持续时间由OS确定,并且代码执行可以随时中断。 如果开发人员要求额外的时间来执行一些代码,则时间可能会更长。 在某些情况下,可以直接在后台模式下启动应用程序。 例如,如果在收到远程推送通知时开始下载某些内容,则该应用程序可以在后台模式下启动。

非活动状态 :通常是启动应用程序的活动状态和背景状态之间的过渡状态。 例如,如果我们在应用程序处于前台状态时收到电话,它将进入非活动状态。

活动 :当应用程序处于前台并且可以接收事件时,它处于活动状态。

已挂起 :当应用程序处于后台状态时,系统将其挂起,并且该应用程序无法执行任何代码。 没有任何有关暂停事件的通知。 系统会自动挂起该应用程序。

我们如何知道何时进行状态转换?

UIApplication是代表我们的应用程序的对象。 它会设置所有内容并启动应用程序运行。 UIApplication对象通过UIApplicationDelegate通知我们。 当UIApplication对象控制系统与应用程序对象之间的通信并管理事件循环时,我们在UIApplicationDelegate对象中编写我们的自定义代码,以处理应用程序的启动以及状态之间的转换以及更多其他事情。

因此,让我们看一下UIApplicationDelegate中调用了哪些方法,以及何时需要在每个方法中添加代码。

  • application(_ application:willFinishLaunchingWithOptions:)

调用willFinishLaunchingWithOptions ,我们知道我们的应用程序的启动过程已启动,主故事板或nib文件已加载,但该应用程序仍处于非活动状态。 如果我们的应用是由于特定原因启动的,例如远程推送通知或主屏幕快捷方式,则此信息将在options 。 这里要了解的重要一点是,在这些情况下,系统可能会调用其他UIApplicationDelegate方法。 例如,如果调用该应用程序以打开URL,则系统将调用application(_:open:options:)方法。 options为我们提供了必要的信息,以便我们对这些事件做出正确的反应。 另一个很好的例子是Twitter feed。 我们可以看到,无论何时终止Twitter iOS应用并再次打开,它都会从我们离开的位置恢复。 它不会一直滚动到顶部。 如果我们要实现相同的状态恢复功能,则所需的步骤之一是在willFinishLaunchingWithOptions调用UIWindowmakeKeyAndVisible()方法,而不是在application(_ application:didFinishLaunchingWithOptions:)方法中调用它。 makeKeyAndVisible方法的工作正在显示窗口。 但是,当我们调用它时,它不会使窗口立即可见。 UIKit等待application(_ application:didFinishLaunchingWithOptions:)首先完成。

  • application(_ application:didFinishLaunchingWithOptions:)

启动过程快要完成并且应用即将准备就绪时,将调用此方法。 因此,我们有空间在启动过程中做一些最后的调整。 与前一个的区别是这次改变了状态,即前景还是背景。 但是尚未显示该应用程序的窗口或任何用户界面。

通过URL启动应用程序时,系统会使用这两种方法的返回值,并将它们组合起来以决定是否应处理URL。 如果它们都返回false ,则不会处理该URL。

  • applicationDidBecomeActive(_ application:)

当应用程序从非活动状态转换为活动状态时,将调用此方法。 重要的是,该应用程序还会发布didBecomeActiveNotification来通知侦听器。 例如,如果我们运行一个计时器来衡量用户在屏幕上花费了多少,我们可能会在发布此通知时重新启动计时器。 另外,我们可以恢复在应用程序变为非活动状态时暂停的所有其他任务。 (例如,打来电话时)

  • applicationWillResignActive(_ application:)

当应用程序即将从活动状态转换为非活动状态时,将调用此方法。 因此,类似于之前的方法,我们可能需要暂停任何任务或计时器。 例如,如果我们要开发游戏,则应在调用此方法时暂停游戏。 此外,该应用程序还将发布willResignActiveNotification来通知侦听器。

  • applicationDidEnterBackground(_ application:)

如果我们想在后台执行一些代码,这是重要的方法之一。 苹果公司说,我们大约需要五秒钟才能完成此方法。 之后,该应用程序将终止并从内存中清除。 如果需要更多时间执行后台代码,则需要调用beginBackgroundTask(expirationHandler:) 。 这里的关键是,在退出此方法之前,我们需要完成UI调整。 例如,当applicationDidEnterBackground返回时,系统为应用程序拍照。 因此,如果屏幕上有敏感数据,则需要在方法返回之前隐藏或修改这些视图。 因此,如果我们的应用程序都试图执行后台代码并更新UI,则应首先调用beginBackgroundTask(expirationHandler:)以请求更多时间,然后在调度队列或另一个线程上运行这些任务。 因此,我们的应用程序既可以进行UI调整,又可以运行后台任务。 最后但并非最不重要的一点是,该应用程序还几乎同时发布了didEnterBackgroundNotification来通知侦听器。

  • applicationWillEnterForeground(_ application:)

当应用程序即将进入前台时,将调用此方法。 始终在此方法后面跟随applicationDidBecomeActive(_ application)方法。

  • applicationWillTerminate(_ application:)

当应用即将终止时,将调用此方法。 我们大约有五秒钟的时间来执行任何任务并返回。 五秒钟后,系统可能会终止整个过程。 在这里要知道的基本要点是,当用户退出应用程序时,通常不会调用此方法。 如果应用程序正在运行后台任务,并且系统希望终止该应用程序,则可以调用此方法。 如我们所见,遗憾的是,这种方法尚不确定。 因此,在此我们不应执行任何关键任务,例如保存用户数据。

关于应用启动,还有一件事需要提及。 启动应用程序时,我们需要尽快准备UI。 稍后我们将讨论线程和并发。 但是,要知道的是,每个UI操作都在主线程上运行。 在实现上述方法时,我们需要异步运行非UI代码。 因此,我们不会阻塞主线程。

我们研究了应用程序生命周期的基础知识和要点。 希望对应用程序的生命周期和状态转换有一个简要的了解。 我们可能需要使我们的应用适应状态转换,以提供更好的用户体验。 了解状态和过渡的基础知识使我们能够开发更强大的应用程序。

您在执行后台任务时会遵循哪些策略? 您如何看待应用程序的生命周期? Apple应该编写更多的委托方法还是您找到一些变通办法来实现您的愿望? 让我知道您在Twitter @candostEN上的想法,评论或反馈。


NS for iOS Devs Series的所有帖子

  • 应用生命周期
  • 查看生命周期
  • 并发
  • 可测性

进一步:

状态转换的图形表示

后台执行编程指南

并发编程指南