0%

iOS APP生命周期

问题:APP进入后台后大概三分钟就被系统kill掉了,再次进入都是重新启动,对用户体验有一定影响.

为了解决这个问题,首先来了解一下一个APP的生命周期.

一、iOS APP生命周期

一个iOS APP生命周期大概有五种状态.

如下图:

  • Not running:app还没运行.
  • Inactive:app运行在前台但不能接收事件.
  • Active:app运行在前台并且能够接收事件.
  • Backgroud:程序在后台并且能够执行代码,大多数程序进入这个状态后会在这个状态上停留一会(一般就几秒钟,如果有申请后台运行大概会停留180s).时间到之后会进入挂起状态(Suspended).但有几种特定类型的APP可以长期处于Backgroud状态.
  • Suspended:程序在后台不能执行代码.系统会自动把程序变成这个状态而且不会发出通知.当挂起时,程序还是停留在内存中的,当系统内存低时,系统就把挂起的程序清除掉,为前台程序提供更多的内存,并且不会发出任何通知.

从上面的图可以看出如果挂起的应用所占用的内存还没有被系统回收,则点击APP图标时,应用会进入后台,然后进入前台,此时看到的仍然是上一次的界面.但当挂起的应用所占用的内存已经被系统回收,则点击APP图标时,相当于重新启动.

了解了APP的生命周期后,可以看到挂起的应用只有在内存紧张的情况下才会被系统清理,这种情况是我们无法控制的.因此出现上述bug极有可能是程序还在运行时就被系统kill掉了.系统主动kill掉一个APP的情况并不多见,主要有如下几种:

  • APP出现闪退
  • APP内存峰值过高
  • APP长时间没有响应事件
  • 某些特殊API的错误使用

由于APP是在后台运行一段时间后被kill掉的,因此极有可能是某些特殊API的错误使用导致的,最终发现是向系统申请后台运行时间的API错误使用导致.

可长期处于后台状态的应用类型

对于需要执行更多执行时间的任务,必须请求特定权限才能在后台运行它们而不会被挂起。在iOS中,只允许在后台运行特定的应用类型:

  • 在后台播放用户可听内容的应用,例如音乐播放器应用
  • 在后台录制音频内容的应用程序
  • 可让用户随时了解其位置的应用,例如导航应用
  • 支持互联网协议语音(VoIP)的应用
  • 需要定期下载和处理新内容的应用
  • 从外部配件接收定期更新的应用程序

二、如何向系统申请后台运行时间

相关方法:

1
2
3
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void(^ __nullable)(void))handler  NS_AVAILABLE_IOS(4_0) NS_REQUIRES_SUPER;
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(nullable NSString *)taskName expirationHandler:(void(^ __nullable)(void))handler NS_AVAILABLE_IOS(7_0) NS_REQUIRES_SUPER;
- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier NS_AVAILABLE_IOS(4_0) NS_REQUIRES_SUPER;

通过beginBackgroundTaskWithExpirationHandler:方法可以向系统申请大约180s(iOS7)的后台运行时间,或者600s(iOS6)运行时间用以处理后台操作.

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- (void)backgroundDoSomethings {
UIApplication *application = [UIApplication performSelector:@selector(sharedApplication)];
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];

// Start the long-running task and return immediately.
[self doSomethingWithCompletionBlock:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
}

- (void)doSomethingWithCompletionBlock:(void (^)(void))completion
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

NSLog(@"开始睡");
sleep(175);
NSLog(@"睡醒");

if (completion) {
completion();
}
});
}

特别注意:
beginBackgroundTaskWithExpirationHandler一定要与endBackgroundTask配对使用,否则时间到后系统将直接kill掉你的APP,从而导致开头出现的问题.

参考

App Programming Guide for iOS

觉得文章有帮助可以打赏一下哦!