程序被送入后台后,向 iOS 借时间,完成长期任务-备

12.2.2. 方案

使用UIApplication的beginBackgroundTaskWithExpirationHandler: 实例方法。在你完成任务后,调用UIApplication的endBackgroundTask:方法。

12.2.3. 讨论

当一个iOS应用被送到后台,它的主线程会被暂停。你用NSThread的detachNewThreadSelector:toTar get:withObject:类方法创建的线程也被挂起了。如果你想在后台完成一个长期任务,就必须调用UIApplication的beginBackgroundTaskWithExpirationHandler:实例方法,来向iOS借点时间。UIApplication的backgroundTimeRemaining属性包含了程序完成他的任务可以使用的秒数。如果在这个期限内,长期任务没有被完成,iOS将终止程序。每个对beginBackgroundTaskWithExpirationHandler:方法的调用,必须要相应的调用endBackgroundTask:方法(UIApplication的另一个实例方法)。也就是说,如果你向iOS要更多时间来完成一个任务,你必须告诉iOS你什么时候能完成那个任务,那时,你的程序将iOS 5 Programming Cookbook www.devdiv.com 翻译整理

DevDiv 翻译:kyelup cloudhsu 耐心摩卡 wangli2003j3 xiebaochun dymx101 jimmylianf BeyondVincent 20 DevDiv 校对:laigb kyelup DevDiv 编辑:BeyondVincent 版本 1.0 | 2012 年 07 月 30 日

和其所有被暂停的线程被放入后台。

当你的程序在前台时,UIApplication的backgroundTimeRemaining属性等于DBL_MAX常量,这是double类型可表示的最大值(和这个值相当的integer通常等于-1)。在iOS被要求在程序被完全挂起之前给于更多的执行时间,这个属性指明了在完成任务前程序拥有多少秒。

在程序中你可以多次调用beginBackgroundTaskWithExpirationHandler:方法。要记住的重点是,当iOS为你的程序返回一个token或者任务标识(task identifier)时,你都必须调用endBackgroundTask:方法,在运行的任务结束时,用来标志任务结束。如果你不这么做的话,iOS会终止你的程序。

在后台时,程序不应该执行完全的功能,也不应该处理大量数据。事实上,他们只应该完成一个长期任务。

比如,一个程序正在调用一个web service API,并且还没有从服务器上的那个API接收到响应。在此期间,如果程序被送入后台,它可以请求更多的时间,直到它从服务器收到响应。一旦响应被接收,程序必须保存其状态,并调用UIApplication的endBackgroundTask:实例方法将任务标记为完成。

让我们看一个例子。我将从在应用程序委托中定义一个UIBackgroundTaskIdentifier类型的属性开始。同时,让我们定义一个NSTimer,当程序被送到后台时,我们将用它每隔1秒向控制台窗口输出一条消息:

#import <UIKit/UIKit.h>

@interface Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate : UIResponder <UIApplicationDelegate>

@property (nonatomic, strong) UIWindow *window;

@property (nonatomic, unsafe_unretained) UIBackgroundTaskIdentifier backgroundTaskIdentifier;

@property (nonatomic, strong) NSTimer *myTimer;

@end

接下来我们继续同步属性:

#import "Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate.h" @implementation Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate

@synthesize window = _window;

@synthesize backgroundTaskIdentifier; @synthesize myTimer;

现在,让我们创建定时器,并在程序被送到后台时启动它:

- (BOOL) isMultitaskingSupported{

BOOL result = NO;

if ([[UIDevice currentDevice]

respondsToSelector:@selector(isMultitaskingSupported)]){ result = [[UIDevice currentDevice] isMultitaskingSupported];

}

return result;

}

- (void) timerMethod:(NSTimer *)paramSender{

NSTimeInterval backgroundTimeRemaining =

[[UIApplication sharedApplication] backgroundTimeRemaining];

if (backgroundTimeRemaining == DBL_MAX){ NSLog(@"Background Time Remaining = Undetermined");

} else { iOS 5 Programming Cookbook www.devdiv.com 翻译整理

DevDiv 翻译:kyelup cloudhsu 耐心摩卡 wangli2003j3 xiebaochun dymx101 jimmylianf BeyondVincent 21 DevDiv 校对:laigb kyelup DevDiv 编辑:BeyondVincent 版本 1.0 | 2012 年 07 月 30 日

NSLog(@"Background Time Remaining = %.02f Seconds",

backgroundTimeRemaining);

} }

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

if ([self isMultitaskingSupported] == NO){

return; }

self.myTimer =

[NSTimer scheduledTimerWithTimeInterval:1.0f

target:self

selector:@selector(timerMethod:) userInfo:nil

repeats:YES];

self.backgroundTaskIdentifier =

[application beginBackgroundTaskWithExpirationHandler:^(void) { [self endBackgroundTask];

}]; }

你可以看到,在后台任务的完成处理者(completion handler)中,我们调用了应用程序委托的endBackgroundTask方法。这是一个我们编写的方法,如下:

- (void) endBackgroundTask{

dispatch_queue_t mainQueue = dispatch_get_main_queue();

__weak Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate *weakSelf = self;

dispatch_async(mainQueue, ^(void) {

Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate *strongSelf = weakSelf;

if (strongSelf != nil){

[strongSelf.myTimer invalidate];

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

strongSelf.backgroundTaskIdentifier = UIBackgroundTaskInvalid; }

}); }

在长期任务结束后,我们需要做一些事情进行清理:

1. 结束所有的线程和定时器,不管他们是基础定时器还是GCD中创建的。

2.调用UIApplication的endBackgroundTask:方法来结束后台任务。

3.将任务标识设置为UIBackgroundTaskInvalid,标志我们的任务结束。

最后,当我们的应用回到前台,如果我们的后台任务还在执行中,我们需要确保我们在干掉它:

- (void)applicationWillEnterForeground:(UIApplication *)application{

if (self.backgroundTaskIdentifier != UIBackgroundTaskInvalid){

[self endBackgroundTask]; }

}

在我们的例子中,不论何时程序被送到后台,我们都会要求更多时间以完成一个长期任务(例如,在这里是我们计时器的代码)。在我们的时间里,我们不断的读取UIApplication实例中backgroundTimeRemaining属性的值,将它打印到控制台。在UIApplication的beginBackgroundTask WithExpirationHandler: 实例方法中,在程序的额外时间内完成一个长期任务之前,我们提供的代码将被执行(一版大概在任务过期前5到10秒)。在此,我们只要调用UIApplication的endBackgroundTask:实例方法来结束任务。

时间: 2024-08-08 13:43:44

程序被送入后台后,向 iOS 借时间,完成长期任务-备的相关文章

iOS解决应用进入后台后计时器和位置更新停止的问题

由于iOS系统为"伪后台"运行模式,当按下HOME键时,如程序不做任何操作,应用会有5秒的执行缓冲时间,随机程序被挂起,所有任务终端,包括计时器和位置更新等操作,但程序打开后台模式开关后,部分任务可以再后台执行,如音频,定位,蓝牙,下载,VOIP,即便如此,程序的后台运行最多可以延长594秒(大概是10分钟).不幸的是,程序在声明后台模式后很有可能在app上架时被拒.基于此,我研究出了不用申明后台模式就能让计时器和定位在app进入前台时继续运行的方法. 实现原理如下: 利用iOS的通知

IOS 后台挂起程序 当程序到后台后,继续完成Long-Running Task 任务

我们知道,到我们程序从前台退到后台(安home)键后,将执行程序的委托方法. // 当应用程序掉到后台时,执行该方法 - (void)applicationDidEnterBackground:(UIApplication *)application { } 我们已经知道: 当一个 iOS 应用被送到后台,它的主线程会被暂停.你用 NSThread 的 detachNewThreadSelector:toTar get:withObject:类方法创建的线程也被挂起了. 我们假设有这么一种情况:

iOS后台挂起程序 当程序到后台后,继续完成Long-Running Task 任务

我们知道,到我们程序从前台退到后台(安home)键后,将执行程序的委托方法. // 当应用程序掉到后台时,执行该方法 - (void)applicationDidEnterBackground:(UIApplication *)application { } 我们已经知道: 当一个 iOS 应用被送到后台,它的主线程会被暂停.你用 NSThread 的 detachNewThreadSelector:toTar get:withObject:类方法创建的线程也被挂起了. 我们假设有这么一种情况:

ios开发-程序压后台后,悄悄的抓取数据~~

我们使用某个app的时候,当我们将程序压到后台之后,我们希望它还能从服务器抓取一些数据,类似微博,微信,qq这些程序压后台 之后,我们依然能看到icon上显示未读数量.但是ios系统是伪多任务操作系统. 当我们将程序压后台之后,大概过1分钟,程序就会被关闭.就不能抓取数据了.很久之前的做法是:压后台之后,播放一个没有声音 的音频,保证程序存活.然后苹果很快发现了这种方法,并禁止了.我们用这种方法提交审核之后,一般都会被苹果驳回.当然,苹果 依然很贴心的给我提供了相应的解决办法.(使用swift演

iOS程序进入后台后仍运行定时器NSTimer

由于本应用需要在应用进入后台后还要进行定时的检测功能,因此对于我来说怎样让APP在进入后台后 保持运行状态是比较大的需求.然后在iOS系统中是很难实现的,不管是 通过 音频还是 定位系统,我查找了一些资料后都是只能申请到十分钟的运行态.没有所谓的长期运行的概念..... 然而在博客中突然看到这篇文章,尝试了下竟然可以运行很久.不管怎么样我还是先试试了......至于苹果是否能审核通过估计又是个难是 具体如下: 本文所讲为其中之一:iOS程序进入后台后十分钟之内就会被系统kill掉,怎么解决呢?我

iOS 程序退到后台,如何继续执行任务

程序从前台退到后,将执行程序的委托方法. - (void)applicationDidEnterBackground:(UIApplication *)application { } 问题: 当应用被送到后台,主线程就会被暂停.用 NSThread 的 detachNewThreadSelector:toTar get:withObject:类方法创建的线程也被挂起. 场景: 应用从前台退到后台 程序执行代理方法 applicationDidEnterBackground.这时候,我们只有很短的

IOS 后台运行申请更多的时间

当应用程序进入后台时,系统会自动回调应用程序委托的applicationDidEnterBackground:方法. 应用可以在该方法中完成转入后台前需要做的准备工作,所有的应用需要做以下事情. 释放所有可以释放的内存. 保存用户数据或状态信息,所有没写入磁盘的文件或信息,在进入后台之前,都应该写入磁盘,因为程序可能在后台被杀死. 进入后台时释放内存 当程序进入后台之后,为了确保获得最佳的用户体验,建议释放那些占用内存较大且可以重新获取的资源—- 这是因为当应用处于后台时,iOS系统会优先终止那

程序自启动及后台持续运行的研究(voip和GPS方式)

1,voip方式    1)首先要修改应用的plist配置,添加下面的设置:        Application does not run in background: NO        Required background modes: VOIP    注:添加这些配置之后,程序重启解锁就会自动运行application:                                  didFinishLaunchingWithOptions方法.    2)主要测试代码:- (BO

解决小程序中Data.parse()获取时间戳IOS不兼容

由于与后台接口必须对比时间戳所以首先得前台获取时间戳.刚开始是获取手机本地时间,但用户改了时间就废了..... 后来就从服务器上获取个时间再转换为时间戳(是不是很操蛋,先从服务器上获取在TM的自己比较),但后台直接给我一个时间戳不就完事了么, 还就给我一个时间自己转然后问题就来了. [csharp] view plain copy var resData = '2017-3-14 10:03:45' console.log("返回时间:" + resData) var time = D