NSTimer在后台的行为(addTimer:,beginBackgroundTaskWithExpirationHandler :) [英] NSTimer behavior in background (addTimer:, beginBackgroundTaskWithExpirationHandler:)

查看:79
本文介绍了NSTimer在后台的行为(addTimer:,beginBackgroundTaskWithExpirationHandler :)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我需要帮助了解我试图在应用程序进入后台后维护单例共享计时器时遇到的奇怪行为.

I need help understanding a strange behavior that I encounter while trying to maintain a singleton shared timer in my application after it enters background.

以前,我并不关心此NSTimer,因为它是使用后台位置服务在后台使用用户位置更新的.

Previously I did not care for this NSTimer as it was updated with user location in the background using background location services.

但是,我想解决用户在后台或位置更新同时拒绝位置更新的情况.该位置和计时器与我的应用密切相关.

However, I would like to address the case where the user rejects location updates while in background or location updates all together. The location and the timer go hand in hand for my app.

我在以下主题和网站帖子中研究了很多信息...

I worked through quite a bit of information in the following threads and website posts...

苹果公司的后台执行程序

http://www.devfright.com/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?

如何在后台创建NSTimer线程?

​​计划在应用程序处于后台的NSTimer吗?

http://www.raywenderlich.com/92428/background -modes-ios-swift-tutorial

iPhone-轮询事件的背景

根据这些信息,我能够派生(2)个方法,通过这些方法可以使计时器运行约8小时,而iOS在分配的180秒后不会终止应用程序. Apple文档承诺的执行时间(3分钟).这是代码:

Out of this information, I was able to derive (2) methods by which to keep the timer running for ~8 hours without iOS terminating the app after the allotted 180 sec. (3 min.) of execution time as promised by Apple documentation. Here is the code:

AppDelegate.h (对于方法1或方法2不变)

AppDelegate.h (unchanged for Method #1 or #2)

#import <UIKit/UIKit.h>

@interface MFAppDelegate : UIResponder <UIApplicationDelegate>
{
    UIBackgroundTaskIdentifier bgTask;
    NSInteger backgroundTimerCurrentValue;
}

@property (retain, nonatomic) NSTimer *someTimer;

@end

AppDelegate.m (方法1)

AppDelegate.m (Method #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)

AppDelegate.m (Method #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语句.但是为了重新创建此问题帖子的结果,我用了500秒.这显然超过了180秒.这是两种方法的结果:

I have simulated the (2) methods overnight for ~8 hr. (28,800 sec.) by adjusting the if statement of (backgroundTimerCurrentValue >= 500). But to recreate the results for this question post, I used 500 sec. which is clearly more than 180 sec. These are the results from both methods:

...在self.someTimer进行500次迭代后,即500秒.

...after 500 iterations of the self.someTimer, i.e. 500 sec.

现在,这很好,但是在使用与Xcode断开连接的iPhone 5s进行测试之后.发生了一些奇怪的事情... 我制作了一个单视图应用程序来检查self.someTimer的值.在标签中.

Now, this was great, but after doing testing with iPhone 5s disconnected from Xcode, etc. Something strange happens... I made a single view application to check the value of the self.someTimer in a label.

长达180秒.标签将使用正确的计时器值更新. 180秒后.有时甚至更快,该应用程序似乎仍然可以从打开的应用程序的幻灯片中选择,但是当我点击屏幕以将该应用程序置于前台时,该应用程序将迅速重新启动.

Up to 180 sec. the label updates with the correct timer value. After 180 sec. and sometimes sooner, the application appears to remain selectable from slide of open apps, however when I tap on the screen to bring the application into foreground the application quickly restarts.

这种行为是Apple承诺的,即180秒后.且没有有效的endBackgroundTask:方法.我认为方法部分是无效的,因为方法2中的UIBackgroundTaskIdentifier类型无效,方法1中的类型为nil.

This behavior is what was promised by Apple, i.e. after 180 sec. and not having a valid endBackgroundTask:method. The method part is what I think is invalid being of type UIBackgroundTaskIdentifier as in method #2 and nil for method #1.

所以我的问题如下:

1)与断开连接时将iPhone插入运行Xcode的Mac时,系统是否允许某些条件发生,例如看似无休止的后台执行?

1) What is different from when the iPhone is plugged into my Mac running Xcode from when it is disconnected, does the system allow certain conditions to occur such as this seemingly endless background execution?

2)我总是可以使用定位服务来启动/停止它们,因此计时器值会根据自上次位置更新以来的时间累积而继续更新,但是有人开发了此代码以实际在断开连接的iPhone上运行?

2) I can always get tricky with location services to start/stop them so that the timer value continues to update from some accumulation of time expired since last location update, but has anyone developed this code to actually run on a disconnected iPhone?

3)如果在问题2中是这样,那么这样的事情是否合法,当我向App Store提交我的应用程序时会被接受吗?

3) And if so in question 2, then is something like this legitimate and will be accepted when I submit my app for App Store?

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

Thanks in advance for your help. Cheers!

推荐答案

是的,通过调试器运行该应用程序可以使其保持活动状态,否则它将在3分钟后终止.因此,您显然不能依赖生产应用程序中的该功能.

Yes, running the app through the debugger will keep it alive when it otherwise would be terminated after 3 minutes. So, you obviously cannot rely upon that feature in a production app.

否,尝试在超过此时间段的时间内使应用程序继续运行是不合法的(除非您已请求适当的后台操作,因为您的应用程序对后台操作具有合法且令人信服的需求,例如,它是音乐播放器,VOIP,导航应用等).苹果可能会拒绝任何与 App Store的2.16部分不符的应用查看指南.

No, attempts to keep the app alive beyond this period of time are not legitimate (unless you have requested proper background operation because your app has legitimate and compelling need for background operation, e.g. it is a music player, VOIP, a navigation app, etc.). Apple is likely to reject any such app that is not in conformance with section 2.16 of the App Store Review Guidelines.

请参见背景执行一章,详细讨论了有效的后台操作.

See the Background Execution chapter of the App Programming Guide for iOS for a fuller discussion of valid background operation.

这篇关于NSTimer在后台的行为(addTimer:,beginBackgroundTaskWithExpirationHandler :)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆