12

我对 iOS/Swift 开发相当陌生,我正在开发一个向 REST API 发出多个请求的应用程序。这是检索“消息”的其中一个调用的示例:

func getMessages() {

    let endpoint = "/api/outgoingMessages"

    let parameters: [String: Any] = [
        "limit" : 100,
        "sortOrder" : "ASC"
    ]

    guard let url = createURLWithComponents(endpoint: endpoint, parameters: parameters) else {
        print("Failed to create URL!")
        return
    }

    do {
        var request = try URLRequest(url: url, method: .get)

        let task = URLSession.shared.dataTask(with: request as URLRequest) { (data, response, error) in

            if let error = error {
                print("Request failed with error: \(error)")
                // TODO: retry failed request
            } else if let data = data, let response = response as? HTTPURLResponse {                
                if response.statusCode == 200 {
                    // process data here
                } else {
                    // TODO: retry failed request
                }
            }
        }

        task.resume()

    } catch {
        print("Failed to construct URL: \(error)")
    }
}

当然,此请求可能因多种不同原因而失败(服务器无法访问、请求超时、服务器返回 200 以外的值等)。如果我的请求失败,我希望能够重试它,甚至可能在下一次尝试之前有延迟。我在 Apple 的文档中没有看到任何关于这种情况的指导,但我发现了一些关于 SO 的相关讨论。不幸的是,这两个都是几年前的,并且在我从未使用过的 Objective-C 中。在 Swift 中做这样的事情是否有任何常见的模式或实现?

4

2 回答 2

10

这个问题是在基于意见的一边播出的,而且相当广泛,但我敢打赌大多数都是相似的,所以就这样吧。

对于触发 UI 更改的数据更新:

(例如,填充数据的表格,或加载图像)一般的经验法则是以非阻碍的方式通知用户,如下所示:

然后有一个下拉刷新控件或刷新按钮。

对于不影响用户操作或行为的后台数据更新:

您可以根据代码轻松地将重试计数器添加到您的请求结果中 - 但我会小心这个并构建一些更智能的逻辑。例如,给定以下状态代码,您可能希望以不同的方式处理事情:

  • 5xx:您的服务器有问题。您可能希望将重试延迟 30 秒或一分钟,但如果它发生 3 或 4 次,您将希望停止对后端进行重试。

  • 401:经过身份验证的用户可能不再被授权调用您的 API。您根本不想重试;相反,您可能希望将用户注销,以便下次他们使用您的应用程序时,系统会提示他们重新进行身份验证。

  • 网络超时/丢失连接:在重新建立连接之前重试无关紧要。您可以围绕可达性处理程序编写一些逻辑,以将后台请求排队,以便在下次网络连接可用时采取行动。

最后,正如我们在评论中提到的,您可能希望查看通知驱动的后台应用程序刷新。在这里,您可以发送通知来告诉应用程序自行更新,而不是轮询您的服务器以获取更改,即使它没有在前台运行。如果您足够聪明,您可以让您的服务器重复通知您的应用程序,直到应用程序确认收到 - 这以一致的方式解决了连接故障和无数其他服务器响应错误代码。

于 2017-10-19T15:52:19.487 回答
7

我将三种处理重试的方法分类:

  1. 可达性重试
  • 可达性是一种奇特的说法,即“当网络连接发生变化时让我知道”。苹果为此提供了一些片段,但它们看起来并不有趣——我的建议是使用类似 Ashley Mill 的Reachability替代品。
  • 除了可达性之外,Apple 还提供了一个waitsForConnectivity(iOS 11+) 属性,您可以在URLSession配置中设置该属性。通过设置它,您会URLSessionDataDelegate在任务等待网络连接时收到警报。您可以利用该机会启用离线模式或向用户显示某些内容。
  1. 手动重试
  • 让用户决定何时重试请求。我想说这最常使用“拉动刷新”手势/UI来实现。
  1. 定时/自动重试
  • 等待几秒钟,然后重试。
  • Apple 的 Combine 框架提供了一种方便的方法来重试失败的网络请求。请参阅使用组合处理 URL 会话数据任务结果
  • 来自Apple Docs:URL 会话的生命周期(已弃用)......但是,您的应用不应立即重试 [a request]。相反,它应该使用可达性 API 来确定服务器是否可达,并且只有在收到可达性已更改的通知时才应该发出新请求。
于 2017-11-03T21:10:46.700 回答