我的应用进入前台时运行的请求失败,并显示“网络连接丢失”

问题描述

后台过渡到前台时,我开始发出请求后,我的应用出现了很多网络错误

错误看起来像这样:

Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo={NSUnderlyingError=0x2808e85a0 {Error Domain=kcfErrorDomainCFNetwork Code=-1005 "(null)" UserInfo={NSErrorPeerAddressKey=<CFData 0x282550410 [0x1f80cb728]>{length = 16,capacity = 16,bytes = 0x10021068c0a8010a0000000000000000},_kcfStreamErrorCodeKey=-4,_kcfStreamErrorDomainKey=4}},NSErrorFailingURLStringKey=http://192.168.1.10:4200/api/users/sessions,NSErrorFailingURLKey=http://192.168.1.10:4200/api/users/sessions,_kcfStreamErrorDomainKey=4,NSLocalizedDescription=The network connection was lost.}

代码是从我的应用的代表触发的:

    func applicationWillEnterForeground(_: UIApplication) {
        coordinator?.handleWillEnterForeground()
    }

this documentation开始,在此阶段应允许网络请求:

在启动时,系统将您的应用程序以非活动状态启动,然后再将其转换为前台。使用您应用的启动时方法来执行当时所需的任何工作。对于处于后台的应用程序,UIKit可通过调用以下方法之一将您的应用程序移至非活动状态:

  • 对于支持场景的应用程序-适当的场景委托对象的sceneWillEnterForeground(_ :)方法
  • 对于所有其他应用程序-applicationWillEnterForeground(_ :)方法

后台过渡到前景时,请使用以下方法从磁盘加载资源并从网络获取数据

此外:

  • 如果我仅在后台输入 1秒钟,则网络请求将成功(当调用完成处理程序时,应用状态将为active
  • 如果我等待 5秒以上,则网络请求将出错(当调用完成处理程序时,应用状态将为inactive

据我所知,inactive状态意味着您无法与用户进行交互并且事件也没有传递。但是网络请求应该可以正常工作,对吗?知道为什么我的应用程序在不活动时无法运行请求吗?

(我还考虑过使用didBecomeActive而不是willEnterForeground,但是在应用启动时也会被调用,所以这并不是我真正需要的。)

编辑:我也碰巧遇到Receive Failed with error "Software caused connection abort"错误,这些错误与此处讨论的问题(即Xcode的多个版本)无关:Xcode error connecting to simulator "Software caused connection abort"

解决方法

我不知道您所描述的错误的根本原因,但我自己遇到了它。正如您所暗示的,Apple似乎在其自己的系统将其标记为苹果之前就告诉应用程序它们处于前台,因此,被激活后立即发出的请求可能会被阻止(这种情况经常发生,但并非100%时间)。

对我有用的解决方案是只需等待十分之一秒。

您可以通过将通话包装在asyncAfter通话中来实现

func applicationWillEnterForeground(_: UIApplication) {
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) { [weak self]
        self?.coordinator?.handleWillEnterForeground()
    }
}

但更可取的是,如果所有请求都通过一个协调器,则让您的AppDelegate代码保持不变,而让协调器查找返回错误代码-1005或53并具有 it 的请求等待十分之一秒,然后重试该请求(确保具有重试限制)。