苹果ios后台执行示例

Posted

技术标签:

【中文标题】苹果ios后台执行示例【英文标题】:Apple's background execution example for ios 【发布时间】:2017-08-24 01:44:09 【问题描述】:

苹果给this of background execution:

- (void)applicationDidEnterBackground:(UIApplication *)application

    bgTask = [application beginBackgroundTaskWithName:@"MyTask" 
    expirationHandler:^
    // Clean up any unfinished task business by marking where you
    // stopped or ending the task outright.
    [application endBackgroundTask:bgTask];
    bgTask = 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, preferably in chunks.

    [application endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
    );

这个示例对我来说从来没有多大意义,我已经看到它被复制到许多后台应用程序示例中。

首先没有意义的是expirationHandler中的这两行:

[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;

bgTask 在块中捕获时似乎没有值。编译器这样抱怨。然后在 dispatch_async 下面的示例中显示了相同的两行。我希望它在 dispatch_async 中,但不在块中。谁能解释为什么我们在块中有这些行?

beginBackgroundTaskWithName 的文档还说“标志着一个新的长期运行的后台任务的开始。”它究竟是如何做到的?什么定义了任务?块范围内是否有任何代码?

【问题讨论】:

It seems like bgTask won't have a value when captured in the block. 为什么不呢?苹果还声明:The bgTask variable is a member variable of the class that stores a pointer to the current background task identifier and is initialized prior to its use in this method. 您可能将后台任务标识符与块混淆了。因此,您可能已经在不持久的范围内声明了标识符。标识符应该在 AppDelegate 中声明为成员变量,只要您的应用程序还活着,它就会一直存在。这就是为什么过期处理程序和 dispatch_async 都可以访问它而无需“复制它”。 @Pochi,不,我没有将标识符与块 ^ 混淆。我所做的是不小心在本地范围内声明它并离开 __block 产生警告“变量'bgTask'在被块捕获时未初始化',但我可能不应该像你说的那样在本地范围内声明它。我引用了这个:hayageek.com/ios-background-task @william:是的,感谢您指出这一点。 【参考方案1】:
bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:]

告诉 iOS 你的应用程序正在启动一个新的后台任务。 iOS 不关心哪个代码构成了任务,它只知道它需要给你的应用更多的时间在后台执行。

此行执行后,bgTask 将包含新的后台任务标识符。

当你的后台任务完成后,你再调用[application endBackgroundTask:bgTask];,iOS知道你的应用已经完成了指定的后台任务,可能不需要更多的后台执行时间(你可能还有其他由beginBackgroundTaskWithName:expirationHandler发起的后台任务优秀)。

行:

bgTask = UIBackgroundTaskInvalid;

只是家务;如果省略此行,不会发生任何不良情况,但 bgTask 将包含无效标识符。

如果您在应用的后台时间到期之前未调用endBackgroundTask,则将调用到期处理程序块。

在到期处理程序中,bgTask 将具有调用 beginBackgroundTaskWithName:expirationHandler 时分配的值,因此这是传递给 endBackgroundTask 的值,再次分配 UIBackgroundTaskInvalid 只是做家务

【讨论】:

所以纠正我:从 iOS 应用程序中的任何位置调用的任何方法通常都会在主线程中执行,除非调用 beginBackgroundTaskWithName 在这种情况下,之后调用的任何方法都将在后台执行,直到 endBackgroundTask叫做。如果 endBackgroundTask 在 beginBackgroundTaskWithName 之后的一定时间内没有被调用,那么 iOS 将终止应用程序。这就是为什么在 exp 处理程序中第二次调用 endBackgroundTask 的原因,以防后台任务没有在我阅读并注意到自己大约 10 分钟的分配时间内完成。 这与您的代码在哪个线程上执行无关。它只是通知您的应用程序想要在后台继续执行任务;通常一个应用程序会在它进入后台后不久被暂停。您的应用在终止前总共有 180 秒的后台执行时间可用。 我仍然不清楚如果 beginBackgroundTaskWithName/endBackgroundTask 对以不同的方法调用会发生什么。例如。在 locationManager:(CLLocationManager *)manager didUpdateLocations 和 applicationDidEnterBackground: 中,我不清楚从 applicationDidEnterBackground 调用重复的 NSTimer。 IE。如果我在没有先调用 beginBackgroundTaskWithName 的情况下调用它,则在应用返回活动状态之前计时器不会触发,但如果我先调用 beginBackgroundTaskWithName,它将无限期运行。 只要一个后台任务没有结束,你的应用就会继续运行,直到达到后台执行时间限制或所有任务都结束。只有在 Xcode 下运行时,计时器才会无限期运行。在正常执行下,您的应用程序将在后台时间 180 秒后终止(当backgroundTimeRemaining 达到 0 时)。在 Xcode 下,当 backgroundTimeRemaining 达到 0 时,您的应用程序会继续运行。 不,我的应用程序在后台运行长达数小时。仅供参考,它具有实时位置共享功能,并且要发送位置数据,它还需要保持网络连接。如果不重置此 iOS 终止时钟,十分钟是我测量的时间。

以上是关于苹果ios后台执行示例的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 中运行后台服务

IOS 13中的iOS后台任务不起作用

快速修复 Appestore 解决 XMPP iOS VoIP 后台执行拒绝

ios后台上传数据

iOS后台运行机制-实践总结

在 iOS 中,后台提取多久执行一次?