在被终止之前的任意时间,应用程序会调用 beginBackgroundTaskWithExpirationHandler:方法让系统给出额外的时间来完成一些需要在后台长时间执行的任务。 (UIApplication的backgroundTimeRemaining属性包含程序运行的总时间)
可以使用task completion去保证那些比较重要但是需要长时间运行的程序不会由于用户切入后台而突然关闭。比如,你可以用这项功能来将用户的信息保存到disk上或者从网络下载一个重要的文件。有两种方式来初始化这样的任务:1、将长时间运行的重要任务用beginBackgroundTaskWithExpirationHandler:和endBackgroundTask:包装。这样就在程序突然切入后台的时候保护了这些任务不被中断。2、当你的应用程序委托 applicationDidEnterBackground:方法被调用时再启动任务中的两个方法必须是一一对应 的,endBackgroundTask:方法告诉系统任务已经完成,程序在此时可以被终止。由于应用程序只有有限的时间去完成后台任务,你必须在超时或 系统将要终止这个程序之前调用这个方法。为了避免被终止,你也可以在一个任务开始的时候提供一个expiration handler和endBackgroundTask:方法。(可以查看backgroundTimeRemaining属性来确定还剩多少时间)。一个程序可以同时提供多个任务,每当你启动一个任务的时 候,beginBackgroundTaskWithExpirationHandler:方法将返回一个独一无二的handler去识别这个任务。你必 须在endBackgroundTask:方法中传递相同的handler来终止该任务。
后台运行的处理代码可以放在- (void)applicationWillResignActive:(UIApplication *)application或者- (void)applicationDidEnterBackground:(UIApplication *)application 中,当然,当程序重新被激活的时候,需要将timer invalidate掉。
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
// if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)])
NSLog(@"Supported background:%@", [UIDevice currentDevice].multitaskingSupported ? @"YES" : @"NO");
UIApplication *app = [UIApplication sharedApplication];
NSLog(@"Remaining time is:%f", app.backgroundTimeRemaining);
__block UIBackgroundTaskIdentifier bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (bgTask != UIBackgroundTaskInvalid) {
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}
});
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i = 0; i < 20; i++) {
UILocalNotification *notification=[[UILocalNotification alloc] init];
if (notification!=nil) {
NSDate *now = [NSDate new];
notification.fireDate = [now dateByAddingTimeInterval:(60 * (i + 1))];//*秒后通知
notification.repeatInterval = 0;//循环次数,kCFCalendarUnitWeekday一周一次
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.applicationIconBadgeNumber = 1; //应用的红色数字
notification.soundName= UILocalNotificationDefaultSoundName;//声音,可以换成alarm.soundName = @"myMusic.caf"
//去掉下面2行就不会弹出提示框
notification.alertBody = [NSString stringWithFormat:@"Time passed:%d minutes", (i + 1)];//提示信息 弹出提示框
notification.alertAction = @"Open"; //提示框按钮
//notification.hasAction = NO; //是否显示额外的按钮,为no时alertAction消失
// NSDictionary *infoDict = [NSDictionary dictionaryWithObject:@"someValue" forKey:@"someKey"];
//notification.userInfo = infoDict; //添加额外的信息
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
[notification release];
}
NSTimer *testTimer = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(doSomeTest) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:testTimer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];
dispatch_async(dispatch_get_main_queue(), ^{
if (bgTask != UIBackgroundTaskInvalid) {
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}
});
});
}
- (void)doSomeTest
{
NSLog(@"background test...");
}