斯威夫特 |后台线程中的网络调用立即超时

Posted

技术标签:

【中文标题】斯威夫特 |后台线程中的网络调用立即超时【英文标题】:Swift | Network call in background thread timing out instantly 【发布时间】:2021-06-08 22:28:33 【问题描述】:

每当应用程序收到新的静默通知时,我都会配置一个本地网络调用,它会触发 setAction(),它是一个 POST 请求,将与刚刚收到的通知相关的信息发送到我们自己的服务器,在前台,网络调用的工作方式为预期,仅当应用程序处于后台时才会出现问题。我 100% 确定 setAction 正在被调用,但 它看起来像在它启动 dataTask 时网络调用超时,我尝试使用线程,但我不确定问题就在那里。

注意事项:

为了确保不是网络问题,我还尝试了其他 HTTP 请求调用配置

如果我快速发送 2 个静默通知,它会触发 1 个 setAction()

  func application(_ application: UIApplication, didReceiveRemoteNotification         userInfo: [AnyHashable: Any],
               fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) 

  // Network call
  tellMe.setAction()

  completionHandler(UIBackgroundFetchResult.newData)

我已经能够检索到的一些“日志”(真实的 https URL 被隐藏起来,例如)。

Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo=_kCFStreamErrorCodeKey=-2103, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <92F80B2F-3D6A-4089-AC76-D160B584712C>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
    "LocalDataTask <92F80B2F-3D6A-4089-AC76-D160B584712C>.<1>"
), NSLocalizedDescription=The request timed out., NSErrorFailingURLStringKey=https://actualURL.com, NSErrorFailingURLKey=https://actualURL.com, _kCFStreamErrorDomainKey=4
The request timed out.

提前谢谢大家,

【问题讨论】:

您在网络请求完成之前呼叫completionHandler。这告诉操作系统可以再次暂停您的应用程序。推迟这个调用,直到你的网络请求完成(但一定要在 30 秒内调用它,否则会发生坏事)。 【参考方案1】:

问题在于,completionHandler 在 http 请求甚至有时间被调用之前就被调用了。解决方法是增加更多时间,如下所示(不是最漂亮的实现,但它有效),

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                     fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) 
        
        // Network call
        tellMe.setAction()
        
        let state = UIApplication.shared.applicationState
        if state == .background 
            //print("App in Background")
            DispatchQueue.main.asyncAfter(deadline: .now() + 29) 
                completionHandler(UIBackgroundFetchResult.newData)
            
         else 
            //print("App in Foreground or Active")
            completionHandler(UIBackgroundFetchResult.newData)
        
    

【讨论】:

您可以避免等待整个 29 秒:创建一个 dispatch_group 并存储它,例如作为应用程序委托的属性。在进行网络调用之前进入组(dispatch_group_enter...),让网络调用在成功或失败时离开调度组,并且 dispatch_group_wait(在 bg 线程上)超时为 29,并调用完成处理程序

以上是关于斯威夫特 |后台线程中的网络调用立即超时的主要内容,如果未能解决你的问题,请参考以下文章

通过 Unity 中的后台线程调用主线程中的函数

无法从 iOS6 中的后台线程调用主线程上的代码

BFTask 在后台绘制 SpriteKit 对象正在锁定主线程

iOs后台线程中的函数调用

后台工作人员中异步等待中的调解员死锁-如何检测线程调用自身

后台线程中的 moya 请求