07iOS应用程序的生命周期

2016-08-01  本文已影响20人  i爱吃土豆的猫

0. 引子

iOS应用程序一般都是由自己编写的代码系统框架(system frameworks)组成,系统框架提供一些基本infrastructure给所有app来运行,而你提供自己编写的代码来定制app的外观和行为。因此,了解iOS infrastructure和它们如何工作对编写app是很有帮助的。

1. Main函数入口

所有基于C编写的app的入口都是main
函数,但iOS应用程序有点不同。不同就是你不需要为iOS应用程序而自己编写main
函数,当你使用Xcode创建工程的时候就已经提供了。除非一些特殊情况,否则你不应该修改Xcode提供的main
函数实现。示例代码如下:

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[])
{ 
     @autoreleasepool { 
           return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 
     } 
}

上面实例代码中有一个很重要的函数UIApplicationMain,它主要是创建app的几个核心对象来处理以下过程:

2.应用程序的架构

2.1 MVC

iOS应用程序都遵循Model-View-Controller
的架构,Model负责存储数据和处理业务逻辑,View负责显示数据和与用户交互,Controller是两者的中介,协调Model和View
相互协作。它们的通讯规则如下:

MVC Stanford University View Model

2.2 几个关键对象

了解iOS的MVC设计模式之后,我们从下图来了解在MVC模式下iOS应用程序有哪些关键对象以及它们职责主要是什么?

The Structure of an App

3. Main Run Loop

一个iOS应用程序的main run loop主要作用是处理所有与用户相关的事件。UIApplication对象在启动时就设置main run loop和使用它来处理事件和更新基于view的界面。正如它名字所示,main run loop是运行在应用程序的主线程。这样就确保与接收到用户相关的事件被有序地处理。

下图显示main run loop的架构和用户事件最终是怎样被应用程序处理。当用户与设备交互时,系统就会生成与交互关联的事件,然后被应用程序的UIKit通过一个特殊的端口来分发。应用程序把事件放入队列,然后逐个分发到main run loop来执行。UIApplication
对象是第一个对象接收到事件,然后决定怎样处理它。一个touch event通常都被分发到main window对象,然后依次分发到发生触碰的view。其他event的接收事件对象路径可能有点不同。

进程

大多数的事件通过使用main run loop来分发,但有些不是。有些事件被发送到一个delegate对象或传递到你提供的block中。想了解更多如何处理大多数类型的事件,其中包括touch、remote control、motion、accelerometer和gyroscopic等事件,请查阅Event Handle Guide for iOS

4. 应用程序的状态和多任务

4.1

有时系统会从app一种状态切换另一种状态来响应系统发生的事件。例如,当用户按下home键、电话打入、或其他中断发生时,当前运行的应用程序会切换状态来响应。应用程序的状态有以下几种:

App状态切换

4.2

大多数发生状态转换时都会调用delegate对象对应的方法来响应app的状态改变。下面汇总了delegate对象的所有方法,当app状态发生转换时,你可能会使用到它们。

4.3

现在讲下app启动、来回切换app和锁屏时状态的切换和调用对应哪些delegate对象的方法:

如图所示,当app启动时,首先由not running状态切换到inactive状态,此时调用application:didFinishLaunchingWithOptions:方法;然后由inactive状态切换到active状态,此时调用applicationDidBecomeActive:方法。

图2

当app发生中断时,由active状态切换到inactive状态,此时调用applicationWillResignActive:方法。

如图所示,当切换到另一个app时,由状态active切换到inactive,此时调用applicationWillResignActive:方法;然后从inactive状态切换到running状态,此时调用applicationDidEnterBackground:方法。

图4

而当切换回本来的app时,由running状态切换到inactive状态,此时调用applicationWillEnterForeground:方法,然后由inactive状态切换到active状态,调用applicationDidBecomeActive:方法。

如何所示,当手机锁屏时,由状态active
切换到inactive
,此时调用applicationWillResignActive:
;然后再由inactive
状态切换到running
状态,此时调用applicationDidEnterBackground:
方法。
更多关于app状态切换以及调用app delegate
哪些方法,请观看WWDC 2011 Session的session_320__adopting_multitasking_in_your_app视频。

5. 应用程序的终止

系统常常是为其他app启动时由于内存不足而回收内存最后需要终止应用程序,但有时也会是由于app很长时间才响应而终止。如果app当时运行在后台并且没有暂停,系统会在应用程序终止之前调用applicationWillTerminate:来保存用户的一些重要数据以便下次启动时恢复到app原来的状态。

6. 总结

本文总结了iOS应用程序从启动到结束过程中有哪些关键对象在参与,以及当用户与系统交互时产生事件时,系统利用main run loop来管理事件循环,决定将事件交给系统哪些对象处理和如何处理。而当app启动、来回切换app和锁屏时,app的状态如何切换和调用对应的哪些app delegate对象来处理。

7. 扩展阅读

App Programming Guide for iOS
Developing iOS 7 App for iPhone and iPad
深入理解RunLoop
Objective-C Autorelease Pool 的实现原理

20180322iOS应用生命周期总结

应用程序的状态:

iOS的入口在main.m文件

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

main函数的两个参数,iOS中没有用到,包括这两个参数是为了与标准ANSI C保持一致。 UIApplicationMain函数,前两个和main函数一样,重点是后两个。

后两个参数分别表示程序的主要类(principal class)和代理类(delegate class)。如果主要类(principal class)为nil,将从Info.plist中获取,如果Info.plist中不存在对应的key,则默认为UIApplication;如果代理类(delegate class)将在新建工程时创建。

根据UIApplicationMain函数,程序将进入AppDelegate.m,这个文件是xcode新建工程时自动生成的。下面看一下AppDelegate.m文件,这个关乎着应用程序的生命周期。

1、application didFinishLaunchingWithOptions:当应用程序启动时执行,应用程序启动入口,只在应用程序启动时执行一次。若用户直接启动,lauchOptions内无数据,若通过其他方式启动应用,lauchOptions包含对应方式的内容。

2、applicationWillResignActive:在应用程序将要由活动状态切换到非活动状态时候,要执行的委托调用,如 按下 home 按钮,返回主屏幕,或全屏之间切换应用程序等。

3、applicationDidEnterBackground:在应用程序已进入后台程序时,要执行的委托调用。

4、applicationWillEnterForeground:在应用程序将要进入前台时(被激活),要执行的委托调用,刚好与applicationWillResignActive 方法相对应。

5、applicationDidBecomeActive:在应用程序已被激活后,要执行的委托调用,刚好与applicationDidEnterBackground 方法相对应。

6、applicationWillTerminate:在应用程序要完全推出的时候,要执行的委托调用,这个需要要设置UIApplicationExitsOnSuspend的键值。

初次启动:

iOS_didFinishLaunchingWithOptions
iOS_applicationDidBecomeActive

按下home键:

iOS_applicationWillResignActive
iOS_applicationDidEnterBackground

点击程序图标进入:

iOS_applicationWillEnterForeground
iOS_applicationDidBecomeActive

当应用程序进入后台时,应该保存用户数据或状态信息,所有没写到磁盘的文件或信息,在进入后台时,最后都写到磁盘去,因为程序可能在后台被杀死。释放尽可能释放的内存。

 - (void)applicationDidEnterBackground:(UIApplication *)application{
 }

方法有大概5秒的时间让你完成这些任务。如果超过时间还有未完成的任务,你的程序就会被终止而且从内存中清除。

如果还需要长时间的运行任务,可以在该方法中调用:

[application beginBackgroundTaskWithExpirationHandler:^{ 
      NSLog(@"begin Background Task With Expiration Handler"); 
 }];

程序终止

程序只要符合以下情况之一,只要进入后台或挂起状态就会终止:

①iOS 4.0以前的系统

②app是基于iOS 4.0之前系统开发的。

③设备不支持多任务

④在Info.plist文件中,程序包含了 UIApplicationExitsOnSuspend 键。

系统常常是为其他app启动时由于内存不足而回收内存最后需要终止应用程序,但有时也会是由于app很长时间才响应而终止。如果app当时运行在后台并且没有暂停,系统会在应用程序终止之前调用app的代理的方法 - (void)applicationWillTerminate:(UIApplication *)application,这样可以让你可以做一些清理工作。你可以保存一些数据或app的状态。这个方法也有5秒钟的限制。超时后方法会返回程序从内存中清除。

注意:用户可以手工关闭应用程序

上一篇下一篇

猜你喜欢

热点阅读