首页 > 代码库 > 让程序支持后台处理

让程序支持后台处理

iOS支持4种主要的后台处理:应用程序挂起、本地通知、任务特定的后台处理和完成长时间运行的后台任务。

iOS4.0以后的设备都已经支持多任务了,如果项目要在更早版本的系统中运行,可以通过下面代码检测设备是否支持多任务:

UIDevice *device = [UIDevice currentDevice];BOOL backgroundSupported = NO;if([device respondsToSelector:@selector(isMultitaskingSupported)]){    backgroundSupported = device.multitaskingSupported;}

先来看一下如何禁用后台处理:

如图所示,在info选项卡的Custom iOS Target Properties属性列表里添加一个新行:”Application does not run in background”,并将值设为YES即可禁用后台处理。

 

挂起

应用程序挂起时,它将暂停执行代码,但保留当前状态。用户返回到应用程序时,它看起来像是一直在运行。实际上,所有的任务都停止了,以免应用程序占用设备的资源。

在应用程序挂起时,除执行清理工作外,还需要负责从挂起状态恢复,并更新在挂起期间将发生变化的应用程序内容(时间/日期等)。

任何应用程序都默认支持后台挂起。为支持后台挂起,只需利用开发工具创建iOS4.0以上的项目即可。

可以创建一个计时器程序,当计数为10时,按home键退出程序,这样你过一段时间再返回程序,发现会从10开始继续计数,而不是挂起时仍然在继续计数。

 

本地通知

下面的代码演示了本地通知的使用,一旦生效,即使程序并没有运行,也会按设定的触发通知。

[[UIApplication sharedApplication] cancelAllLocalNotifications];UILocalNotification *localNotif = [[UILocalNotification alloc] init];localNotif.applicationIconBadgeNumber = 1;localNotif.fireDate = [NSDate dateWithTimeIntervalSinceNow:5];localNotif.timeZone = [NSTimeZone defaultTimeZone];localNotif.repeatInterval = NSMinuteCalendarUnit;localNotif.soundName = @"msg.wav";localNotif.alertBody = @"This is a notice!";[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];

 

UILocalNotification *localNotif = [[UILocalNotification alloc] init];

这行代码取消了应用程序以前可能调度了的所有通知,以提供干净的平台。

UILocalNotification类的各属性释义:

applicationIconBadgeNumber — 触发通知时显示在应用程序图标中的徽章计数。

fireDate — 一个NSDate对象,指定通知将在未来的什么时间触发。

timeZone — 用于调度通知的时区。几乎总是设置为本地时区,即[NSTimeZone defaultTimeZone]。

repeatInterval — 重复触发通知的频率。可选择的值可能有NSDayCalendarUnit(每天)、NSHourCalendarUnit(每小时)、和NSMinuteCalendarUnit(每分钟)等。

soundName — 一个字符串(NSString),包含通知触发时将播放的声音源。

alertBody — 一个字符串,包含要向用户显示的文本消息。

 

[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];

开始调度通知

 

任务特定的后台处理

这种情况有一个很典型的应用,就是后台音乐播放:我们在程序里播放一首歌曲,当按下Home键或屏幕进入待机,我们仍然希望音乐继续播放。

首先建立简单代码:

#import "ViewController.h"@interface ViewController ()@property (nonatomic,strong) AVAudioPlayer *audioPlayer;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];        //播放音频之前先要设置AVAudioSession模式,设为AVAudioSessionCategoryPlayback即可。模式意义及其他模式请参考文档。    AVAudioSession *session = [AVAudioSession sharedInstance];    [session setActive:YES error:nil];    [session setCategory:AVAudioSessionCategoryPlayback error:nil];        NSString *strSoundFile = [[NSBundle mainBundle] pathForResource:@“mymusic1” ofType:@"mp3"];        self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:strSoundFile] error:nil];    self.audioPlayer.delegate = self;    [self.audioPlayer play];}- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{    NSLog(@"播放结束");}- (void)didReceiveMemoryWarning{    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}@end

然后需要选择项目的顶级编组,并单击目标—项目名,展开Custom iOS Target Properties选项卡,在属性列表里添加一行名为”Required background modes”的Key,然后展开这个键,在其中添加一个新值:”App plays audio or streams audio/video using AirPlay”。

修改保存后,再次运行程序,并按下home键返回,将发现音乐会继续在后台播放。另一个比较典型的应用就是定位服务,需要添加”App registers for location updates”。

 

完成长时间运行的后台任务

对于每项要启用后台完成的任务,都需要有自己的UIBackgroundTaskIdentifier。初始化方式如下:

UIBackgroundTaskIdentifier counterTask = [[UIApplication sharedApplication]                                         beginBackgroundTaskWithExpirationHandler:^{                                                //超时后的处理                                                NSLog(@"超时");                                         }];

完成初始化的同时也正式开启了后台处理,要停止后台处理,可以做如下操作:

[[UIApplication sharedApplication] endBackgroundTask:self.counterTask];

每个程序的后台处理时间是有限的,一般只有几分钟;通过UIApplication的backgroundTimeRemaining属性可以查询后台处理剩余时间:

NSTimeInterval timeInterval = [[UIApplication sharedApplication] backgroundTimeRemaining];int hour = (int)(timeInterval/3600);int minute = (int)(timeInterval - hour*3600)/60;int second = timeInterval - hour*3600 - minute*60;NSLog(@"%@",[NSString stringWithFormat:@"%d时%d分%d秒", hour, minute,second]);

下面创建了一个不停计数的程序,运行后尝试退出程序(不是结束程序),过一段时间后返回程序,发现计数还在后台进行,而不是像之前挂起那样暂停计数:

#import "ViewController.h"@interface ViewController ()@property (nonatomic) UIBackgroundTaskIdentifier counterTask;@property (strong, nonatomic) IBOutlet UILabel *lblNum;@property (nonatomic) int count;@property (nonatomic,weak) NSTimer *myTimer;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];        self.counterTask = [[UIApplication sharedApplication]                                             beginBackgroundTaskWithExpirationHandler:^{                                                    //超时后的处理                                                    NSLog(@"超时");                                             }];        self.myTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(countUp) userInfo:nil repeats:YES];}- (void)countUp{    if(self.count==600)    {        [self.myTimer invalidate];        [self setMyTimer:nil];        [[UIApplication sharedApplication] endBackgroundTask:self.counterTask];    }    else    {        self.count++;        self.lblNum.text = [[NSString alloc] initWithFormat:@"%d",self.count];    }}- (void)didReceiveMemoryWarning{    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}@end