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

2024-06-30

Xcode 6.3.1 ARC 启用,适用于 iOS 8.3

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

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

但是,我想解决用户在后台拒绝位置更新或一起拒绝位置更新的情况。对于我的应用程序来说,位置和计时器是齐头并进的。

我在以下线程和网站帖子中研究了相当多的信息.​​.....

Apple 的 - 后台执行 https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW3

http://www.devfright.com/ios-7-background-app-refresh-tutorial/ 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 http://www.infragistics.com/community/blogs/stevez/archive/2013/01/24/ios-tips-and-tricks-working-in-the-background.aspx

如何让我的应用程序在后台运行 NSTimer? https://stackoverflow.com/questions/9220494/how-do-i-make-my-app-run-an-nstimer-in-the-background

如何在后台线程上创建 NSTimer? https://stackoverflow.com/questions/8304702/how-do-i-create-a-nstimer-on-a-background-thread

当应用程序在后台时安排 NSTimer? https://stackoverflow.com/questions/8415870/scheduled-nstimer-when-app-is-in-background

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

iPhone - 后台投票事件 https://stackoverflow.com/questions/4656214/iphone-backgrounding-to-poll-for-events

根据这些信息,我能够推导出 (2) 种方法,使计时器保持运行约 8 小时,而 iOS 不会在分配的 180 秒后终止应用程序。 Apple 文档承诺的执行时间(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 语句。但为了重新创建此问题帖子的结果,我使用了 500 秒。这显然超过了 180 秒。以下是两种方法的结果:

... self.someTimer 迭代 500 次后,即 500 秒。

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

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

这种行为是苹果所承诺的,即 180 秒后。并且没有有效的 endBackgroundTask: 方法。方法部分是我认为无效的 UIBackgroundTaskIdentifier 类型,如方法#2 和 nil 对于方法#1。

所以我的问题如下:

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

2)我总是可以通过位置服务来启动/停止它们,以便计时器值从上次位置更新以来过期的时间累积中继续更新,但是有人开发了这段代码来实际在断开连接的iPhone上运行吗?

3)如果问题2是这样,那么当我向App Store提交我的应用程序时,这样的东西是否合法并且会被接受?

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


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

不,尝试让应用程序在这段时间内保持活动状态是不合法的(除非您已请求适当的后台操作,因为您的应用程序对后台操作有合法且迫切的需求,例如,它是音乐播放器、VOIP、导航应用程序等.)。 Apple 可能会拒绝任何不符合第 2.16 条规定的此类应用程序。应用商店审查指南 https://developer.apple.com/app-store/review/guidelines/.

See the 后台执行 https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW1的章节iOS 应用程序编程指南更全面地讨论有效的后台操作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

NSTimer 在后台的行为(addTimer:, beginBackgroundTaskWithExpirationHandler:) 的相关文章

随机推荐

  • 如何将 Three.js 代码实施到 Android 移动应用程序中?

    我用 HTML CSS 和 JS 编写了 Three js 场景的代码 显示 3D 头部模型及其上的标记 它适用于我的 Angular 项目 我还可以通过将 HTML 代码添加到 Web 视图中 使其在适用于 Android 和 iOS 的
  • 在 Azure Active Directory (AAD) 中注册微服务以确保安全

    我在服务结构集群中部署了一个服务结构应用程序 无状态和有状态 我正在尝试在应用程序中实现安全性 应用程序使用 Active Directory 身份验证库 ADAL 通过 OAuth 2 0 客户端凭据流从 Azure AD 获取令牌 其中
  • 如何在流体宽度表中使用省略号而不使每列大小相同?

    假设我的表中的列是id name description and phone The description列的长度为 1 255 个字符 但 id 最多只有 3 个字符 我希望列的大小适当 而不是每列的大小相同 我想要descriptio
  • A-Frame Super Hands 旋转抓取的物体

    我正在研究 A Frame A Frame 物理和 Super Hands 我有一个简单的场景 可以在其中放置一个对象 现在只是一个盒子 和一些控制器 当我在 VR 中查看这个场景时 我可以抓住盒子 移动它并调整它的大小 但我无法旋转或旋转
  • 在 Android 上下载时播放视频

    是否可以使用安全的 asp net 应用程序在 Android 上下载视频时流式传输视频 我有一个 https 安全的 ASP NET Web 应用程序 该应用程序专门为移动设备 例如 Iphone BB Android 等 制作 称为 M
  • 过滤返回错误结果的自定义适配器

    Check 我正在尝试在我的上实施过滤器ListView 但我面临着一个非常奇怪的问题 如果我输入字母T in the EditText the ListView充满了从以下开始的名字B J 请帮忙 public class MyCusto
  • 如何为子控制台应用程序使用单独的控制台窗口?

    Windows 10 C NET Core 3 1 我想要多个控制台窗口用于输出 例如 在一个显示器上 我想放置一个控制台窗口 它将仅显示错误输出 在另一个显示器上 我想放置一组其他控制台窗口 它将显示各种报告 所有这些控制台窗口都是只读的
  • AudioQueueStart 报告不支持的格式

    我试图让音频队列在 iPhone 应用程序上工作 每当调用 AudioQueueStart 时 它都会给出 fmt 结果代码 kAudioFormatUnsupportedDataFormatError 在下面的代码中 我将格式设置为 kA
  • 如何在 PHP 中打开从第 X 行到第 Y 行的文件?

    我在 PHP 文档中看到的最接近的是 fread 给定的长度 但这并没有指定从哪一行开始 还有其他建议吗 是的 您可以轻松地做到这一点SplFileObject seek http de php net manual en splfileo
  • 从亚马逊 s3 流式传输文件

    我在尝试从 amazon s3 流式传输文件时遇到问题 基本上 我的文件存储在 amazom s3 上 我无法提供对这些文件的直接访问 因为用户需要进行身份验证 我正在尝试找到一种流式传输文件的方法 而无需将每个文件从亚马逊下载到我的服务器
  • 使用 UIPopoverPresentationController 时如何对 PreferredContentSize 进行动画处理?

    我只需设置即可成功更改我呈现的弹出框的框架preferredContentSize 我现在想为内容大小的变化设置动画 但我没有成功 它只是立即更新 事实上我设置的延迟甚至没有得到尊重 如何以动画方式呈现内容大小的变化 In viewDidA
  • 关于 java 中复杂结构的建议(DAO 和服务层链接/耦合)

    介绍 我正在尝试使用 Java 接口 抽象类和泛型创建一个相当复杂的结构 由于没有泛型经验 并且在创建良好的 OOP 设计方面只有一般经验 这开始被证明是一个相当大的挑战 我有一种感觉 我想做的事实际上无法完成 但我可以足够接近它 我将尝试
  • 上传并 POST 文件到 PHP 页面

    我需要一种上传文件并将其 POST 到 php 页面的方法 php 位于 apache 服务器上 我在我的桌面应用程序中使用这个 C 代码 这是一个c代码的套接字 当我执行程序时 可以得到 文件大小为772906 打开服务器正常 文件大小为
  • 将音频添加到 OpenCV 生成的视频中

    我一直在使用python下的OpenCV http opencv willowgarage com documentation python index html从捕获设备录制视频 每小时写入两个输出 AVI 每小时开始时文件名都会更改 其
  • 命令“php”无法识别,但它已在 Windows PATH 中注册

    我在 Windows 服务器上的 PATH 字符串中设置了 C Ampps php 但是当我在 PHPStorm 终端上键入 php 时 总是给出 php is not recognized as an internal or extern
  • excel vba - 在电子表格上查询

    如果我有这两张表 is there some sort of excel vba code using ADO that could acheive these desired results which could utilise any
  • 允许跨域ajax请求

    在我的项目中 我需要允许其他人向我的脚本发送 ajax 请求 因此 外部请求可能来自其他网站和域 也可能来自浏览器扩展 我在脚本顶部简单地添加了这两行 让他们执行此操作 header Access Control Allow Origin
  • Websocket 的基本身份验证

    当我使用 chrome 创建新的 websocket 时 new WebSocket ws gert email protected cdn cgi l email protection 8001 dbname Nodejs服务器接收 GE
  • 如何使用 makecert 创建证书颁发机构证书?

    我正在尝试创建一个使用 SSL 和自签名证书的网站 这就是我所做的 创建权威证书 makecert n CN root signing authority r sv root pvk root cer 创建目标证书 makecert r p
  • NSTimer 在后台的行为(addTimer:, beginBackgroundTaskWithExpirationHandler:)

    Xcode 6 3 1 ARC 启用 适用于 iOS 8 3 我需要帮助理解我在应用程序进入后台后尝试在应用程序中维护单例共享计时器时遇到的奇怪行为 以前我不关心这个 NSTimer 因为它是使用后台位置服务在后台更新用户位置的 但是 我想