NSTimer在后台的行为(addTimer:,beginBackgroundTaskWithExpirationHandler :)

Xcode 6.3.1 ARC已启用,适用于iOS 8.3

我需要帮助了解一个奇怪的行为,当我尝试在应用程序进入后台后维护一个单例共享计时器的时候遇到了一个奇怪的行为。

以前我不关心这个NSTimer,因为它使用后台位置服务在后台更新用户位置。

但是,我想解决的情况是用户在后台或位置更新时拒绝位置更新。 位置和计时器为我的应用程序携手共进。

我在下面的主题和网站post中通过了相当多的信息。

苹果公司的后台执行

iOS 7 Background App Refresh Tutorial

http://www.infragistics.com/community/blogs/stevez/archive/2013/01/24/ios-tips-and-tricks-working-in-the-background.aspx

如何让我的应用程序在后台运行NSTimer?

如何在后台线程上创buildNSTimer?

计划NSTimer当应用程序在后台?

Background Modes Tutorial: Getting Started

iPhone – 背景调查事件

在这些信息之外,我能够推导出(2)使计时器运行约8小时,而没有iOS在180秒之后终止应用程序的方法。 (3分钟)的执行时间,苹果公司的文件承诺。 这里是代码:

AppDelegate.h (方法#1或#2未更改)

#import <UIKit/UIKit.h> @interface MFAppDelegate : UIResponder <UIApplicationDelegate> { UIBackgroundTaskIdentifier bgTask; NSInteger backgroundTimerCurrentValue; } @property (retain, nonatomic) NSTimer *someTimer; @end 

AppDelegate.m (方法#1)

<…

 - (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. NSLog(@"applicationDidEnterBackground"); backgroundTimerCurrentValue = 0; [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil]; self.someTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:true]; [[NSRunLoop currentRunLoop] addTimer:self.someTimer forMode:NSRunLoopCommonModes]; } - (void)timerMethod { NSTimeInterval backgroundTimeRemaining = [[UIApplication sharedApplication] backgroundTimeRemaining]; if (backgroundTimeRemaining == DBL_MAX) { NSLog(@"Background Time Remaining = Undetermined"); } else { NSLog(@"Background Time Remaining = %0.2f sec.", backgroundTimeRemaining); } if (!someBackgroundTaskStopCondition) { [self endBackgroundTask]; } else { nil; } } 

……>

AppDelegate.m (方法2)

<…

 - (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. NSLog(@"applicationDidEnterBackground"); backgroundTimerCurrentValue = 0; bgTask = UIBackgroundTaskInvalid; self.backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{ [application endBackgroundTask:bgTask]; }]; self.someTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:true]; } - (void)timerMethod { NSTimeInterval backgroundTimeRemaining = [[UIApplication sharedApplication] backgroundTimeRemaining]; if (backgroundTimeRemaining == DBL_MAX) { NSLog(@"Background Time Remaining = Undetermined"); } else { NSLog(@"Background Time Remaining = %0.2f sec.", backgroundTimeRemaining); } if (backgroundTimerCurrentValue >= 500) { backgroundTimerCurrentValue = 0; [self.someTimer invalidate]; [[UIApplication sharedApplication] endBackgroundTask:bgTask]; } else { NSLog(@"backgroundTimerCurrentValue: %ld", backgroundTimerCurrentValue); backgroundTimerCurrentValue++; } } 

……>

我已经模拟了(2)方法过夜约8小时。 (28,800秒),通过调整(backgroundTimerCurrentValue> = 500)的if语句。 但要重新创build这个问题的结果,我用了500秒。 这显然超过了180秒。 这是两种方法的结果:

在这里输入图像说明

… 500次迭代之后,即500秒。

在这里输入图像说明

现在,这是伟大的,但经过与Xcode断开连接的iPhone 5stesting之后,发生了一些奇怪的事情…我做了一个单一的视图应用程序来检查标签中的self.someTimer的值。

长达180秒 标签用正确的计时器值更新。 180秒后 有时候,应用程序似乎仍然可以从打开的应用程序的幻灯片中select,但是当我点击屏幕以将应用程序放到前台时,应用程序将很快重新启动。

这是苹果公司承诺的行为,即在180秒后。 并没有有效的endBackgroundTask:方法。 方法部分是我认为是无效的typesUIBackgroundTaskIdentifier方法#2和零方法#1。

所以我的问题如下:

1)当iPhone连接到运行Xcode的Mac从断开连接到iPhone时有什么不同,系统是否允许发生某些情况,如看似无限的后台执行?

2)我可以随时使用定位服务来启动/停止它们,以便计时器值可以持续更新自上次位置更新后过期的累计时间,但是有人开发了这个代码来实际运行在断开的iPhone上吗?

3)如果问题2中有这样的话,那么这个合法的东西,当我提交我的应用程序的应用程序商店将被接受?

在此先感谢您的帮助。 干杯!

是的,通过debugging器运行应用程序将保持活动,否则将在3分钟后终止。 所以,你显然不能依靠生产应用程序中的这个function。

不,试图让应用程序超过这段时间是不合法的(除非您已经请求适当的后台操作,因为您的应用程序有合法和迫切的后台操作需要,例如,它是一个音乐播放器,VOIP,导航应用程序等)。 苹果可能会拒绝任何不符合“ App Store评论指南”第2.16条的应用程序 。

请参阅iOS应用程序编程指南的后台执行章节,以获得有效后台操作的更完整的讨论。