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

问题描述 投票:0回答:2

当我从后台转换到前台时开始发出请求后,我的应用程序出现了相当多的网络错误。

错误看起来像这样:

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, _kCFStreamErrorCodeKey=-4, NSLocalizedDescription=The network connection was lost.}

代码是从我的应用程序的委托触发的:

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

本文档来看,此阶段应允许网络请求:

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

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

从后台转换到前台时,使用这些方法从磁盘加载资源和从网络获取数据

此外:

  • 如果我进入后台仅 1 秒,网络请求就会成功(当完成处理程序被调用时,应用程序状态将为
    active
  • 如果我等待超过 5 秒,网络请求将出错(当调用完成处理程序时,应用程序状态将为
    inactive

根据我的理解,

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

(我也考虑过使用

didBecomeActive
而不是
willEnterForeground
,但它也会在应用程序启动时被调用,所以它并不是我真正需要的。)

编辑:我也碰巧收到与此处讨论的问题无关的

Receive failed with error "Software caused connection abort"
错误(即Xcode的多个版本):Xcode错误连接到模拟器“软件导致连接中止”

ios swift appdelegate
2个回答
6
投票

我不知道你所描述的错误的根本原因,但我自己也遇到过。 正如您所提到的,Apple 似乎在应用程序自己的系统将其标记为前台之前就告诉应用程序它们位于前台,因此在变为活动状态后立即发出的请求可能会被阻止(这种情况经常发生,但不是 100%)以我的经验来看)。

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

您可以通过将您的呼叫包装在

asyncAfter
呼叫中来实现此目的

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

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


0
投票

我遇到了同样的问题,并且在 beginBackgroundTask(expirationHandler:) 中包装请求对我有用

© www.soinside.com 2019 - 2024. All rights reserved.