让程序支持后台处理

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

 

 

posted @ 2014-08-13 15:41  CoderWayne  阅读(3522)  评论(0编辑  收藏  举报