我是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中是否有任何常见的模式或实现方式?
答案 0 :(得分:5)
这个问题在基于意见的方面播出,并且相当广泛,但我敢打赌大多数都是相似的,所以这里就是这样。
对于触发UI更改的数据更新:
(例如填充数据或图像加载的表格)一般的经验法则是以非阻碍的方式通知用户,如下所示:
然后有一个pull-to-refresh控件或刷新按钮。
对于不会影响用户操作或行为的后台数据更新:
您可以根据代码轻松地在请求结果中添加重试计数器 - 但我要小心这一点并构建一些更智能的逻辑。例如,给定以下状态代码,您可能希望以不同的方式处理事情:
5xx:您的服务器出了问题。您可能希望延迟重试30秒或一分钟,但如果它发生3或4次,您将会想要停止锤击您的后端。
401:经过身份验证的用户可能无法再被授权调用您的API。你根本不想重试这个;相反,您可能希望将用户注销,以便下次他们使用您的应用时,系统会提示他们重新进行身份验证。
网络超时/丢失连接:在重新建立连接之前,重试无关紧要。您可以在可达性处理程序周围编写一些逻辑,以便在下次网络连接可用时对后台请求进行排队。
最后,正如我们在评论中提到的那样,您可能希望查看通知驱动的后台应用程序刷新。这是在不用轮询服务器进行更改的情况下,您可以发送通知,告诉应用程序即使在前台未运行时也要自行更新。如果您足够聪明,可以让您的服务器重复通知您的应用,直到应用确认收到 - 这将以一致的方式解决连接失败和无数其他服务器响应错误代码。
答案 1 :(得分:2)
我将三种处理重试的方法分类:
waitsForConnectivity
(iOS 11+)属性,您可以在URLSession
配置中设置该属性。通过设置,当任务正在等待网络连接时,您将通过URLSessionDataDelegate
收到警报。您可以利用该机会启用离线模式或向用户显示内容。