【问题标题】:Execute function every X minutes in background doesn't work在后台每 X 分钟执行一次功能不起作用
【发布时间】:2014-06-12 08:39:43
【问题描述】:

我使用此代码每 X 分钟执行一次函数:

- (void)executeEveryOneMinute
{
    [self myFunction];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        [self executeEveryOneMinute];

    });
}

当应用程序处于前台时它可以工作。
但是当应用程序进入后台时,它就不再工作了。
当我再次将应用程序返回到前台时,它会执行一次函数。
并继续每分钟再次调用函数。

那么如何让它在后台也能工作呢?

【问题讨论】:

    标签: ios iphone objective-c ios7 nsthread


    【解决方案1】:

    请参阅iOS App Programming Guide: App States and Multitasking 的后台执行和多任务处理部分,了解有关可能性的讨论。例如,您可以让应用程序在后台运行几分钟,以完成一些有限长度的任务。或者,如果应用程序正在执行非常特殊的功能列表之一(引用自上述文档),您可以继续在后台运行该应用程序更长的时间:

    • 在后台向用户播放有声内容的应用,例如音乐播放器应用
    • 在后台录制音频内容的应用程序。
    • 让用户随时了解其位置的应用,例如导航应用
    • 支持互联网协议语音 (VoIP) 的应用
    • 需要定期下载和处理新内容的应用
    • 从外部附件接收定期更新的应用

    实现这些服务的应用必须声明它们支持的服务并使用系统框架来实现这些服务的相关方面。声明服务可以让系统知道您使用了哪些服务,但在某些情况下,实际上是系统框架阻止了您的应用程序被挂起。

    但是,iOS 电池/电源管理的基本设计原则是随机应用不能(也不应该)继续在后台运行。但是,如果您分享您正在尝试做什么(即您在 executeEveryOneMinute 方法中具体做什么),如果可能的话,我们可以就如何达到预期效果提供建议。


    如果您尝试在后台继续上传,在 iOS 7 及更高版本中,您应该考虑将NSURLSession 与后台会话配置一起使用([NSURLSessionConfiguration backgroundSessionConfiguration:identifier];在 iOS 8 中有类似的方法)。这将继续尝试上传(自动,无需您进一步干预),不仅在您的应用程序离开前台之后,甚至在应用程序终止后(例如由于内存压力或崩溃)。 AFNetworking 提供了一个基于NSURLSession 的类AFURLSessionManager,它支持这一点(尽管它不是基于NSOperation)。这样一来,您就可以享受后台上传的乐趣,同时也符合 Apple 关于后台操作的指导方针,尤其是与每 60 秒重试一次相比,对电池的影响更小。

    我建议你参考 WWDC 2013 视频What’s New in Foundation Networking 的后半部分,它演示了这个过程(他们正在下载,但上传的想法是一样的)。

    【讨论】:

    • 这就是我想要做的。我在本地数据库中有一些数据(在电话上),必须确保将它们发送到服务器。我正在使用 AFNetworking 将数据传递给服务器。如果用户第一次尝试上传数据但失败(例如没有互联网,或者服务器关闭),我将其保存在本地数据库中,我需要每隔几分钟尝试将其发送到服务器,直到成功。我不知道是否有更好的方法来做到这一点。
    • @1110 iOS7 提供后台上传功能,为您做到这一点。 AFNetworking 还提供基于NSURLSession 的类AFURLSessionManager。请参阅我的答案的附录。
    【解决方案2】:

    定时器在主线程上工作。当应用程序进入后台时,它的计时器变得无效。因此,当应用程序进入后台时,您不能这样做。

    【讨论】:

    • 我该怎么做才能在前台/后台进行这项工作?
    【解决方案3】:

    您不能在计时器的帮助下执行此操作,因为它将在后台失效。你可以试试看this。

    【讨论】:

    • 你能给我举个例子吗?
    【解决方案4】:

    你应该使用后台任务来实现你想要的

    UIApplication*    app = [UIApplication sharedApplication];
    task = [app beginBackgroundTaskWithExpirationHandler:^{
            [app endBackgroundTask:task];
            task = UIBackgroundTaskInvalid;
        }];
    // Start the long-running task and return immediately.
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
            // Do the work associated with the task.
            NSLog(@"Started background task timeremaining = %f", [app backgroundTimeRemaining]);
            if (connectedToNetwork) {
                // do work son...
            }
    
            [app endBackgroundTask:task];
            task = UIBackgroundTaskInvalid;
        });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-03
      • 1970-01-01
      • 2017-04-12
      • 2013-06-25
      • 1970-01-01
      • 2019-11-04
      相关资源
      最近更新 更多