[英]iOS: How to access and use API response data from REST SwiftUi
首先,我对 iOS 开发和 Swift 真的很陌生(从 PHP 来这里两周 :))
我正在创建一个应用程序,它对我非常简单的 api 进行了标注。 我正在使用下面的代码,但无法访问代码的“if let response”部分,也无法从 api 返回的数据中获取“Comments”的值。 想知道是否有人可以提供帮助。
数据恢复正常
//Print out fine
print(str)
将打印我对{"Comments":"success"}
的回复
所以只是想知道如何正确使用这些数据并检查是否成功等
谢谢
func loadData() {
guard let url = URL(string: "myapi.php") else {
print("Your API end point is Invalid")
return
}
let request = URLRequest(url: url)
print("hello1")
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
print("hello2")
let str = String(decoding: data, as: UTF8.self)
//Print out fine
print(str)
// Cannot enter this if statement
if let response = try? JSONDecoder().decode([TaskEntry].self, from: data) {
DispatchQueue.main.async {
print("hello3")
print(response)
}
return
}
}
}.resume()
}
struct TaskEntry: Codable {
public var Comments: String
}
根据您提供的描述,返回您的 API 的 JSON 如下:
{
"Comments": "success"
}
那正确吗?
如果是,这部分代码
if let response = try? JSONDecoder().decode([TaskEntry].self, from: data)
标记您将从应用程序获取的数据解码为数组。 您在此处[TaskEntry].self
为您的数据指定了一个 TaskEntry 数组,这是不正确的,您需要try? JSONDecoder().decode(TaskEntry.self, from: data)
try? JSONDecoder().decode(TaskEntry.self, from: data)
如果你希望一个数组你的 api 必须返回这样的东西
[
{
"Comments": "success"
}
]
为了检查状态码是否正确,我提供了对您的代码进行解释的重构。
首先,Codable 协议用于使用 Encoders 和 Decoders 对数据进行解码和编码。 在这种情况下,您正在使用 JSON,因此您使用 JSONDecoder 来解码数据。 你只需要解码,所以使用 Decodable 协议就足够了。 您不需要将 Comments 标记为 public,因为您在项目中使用 TaskEntry,所以默认情况下(未指定)它是内部的。 此外,您不需要 var,因为您没有更改属性。 此外,作为标准的属性以小写字母开头,因此您可以使用 CodingKeys 来保持质量代码标准。
您可以在Apple Developer 网站中查看
struct TaskEntry: Decodable {
let comments: String
enum CodingKeys: String, CodingKey {
case comments = "Comments"
}
}
然后,您应该考虑您的 Api 错误并对其进行定义。 我给你举个例子:
enum NetworkErrors: Error {
case responseIsNotHTTP
case noDataProvided
case unknown
}
您的负载 function 应该与外部 class 通信或构造 TaskEntry 或错误。 您可以使用带有 Result 的闭包。 请检查链接Hacking with Swift 。 这有两种具有关联值的案例,失败和成功。
此外,您的 UrlSessionTask 的响应需要转换为 HTTPURLResponse 以获取响应 http 状态代码。 我用你的代码提供了一个例子。
func loadData(result: @escaping (Result<TaskEntry, Error>) -> Void) {
guard let url = URL(string: "myapi.php") else {
result(.failure(URLError(.badURL)))
return
}
let request = URLRequest(url: url) // your method is Get, if not you need to set the http method of the request
URLSession.shared.dataTask(with: request) { data, response, error in
guard let response = response as? HTTPURLResponse else {
if let error = error {
print(error.localizedDescription)
result(.failure(error))
} else {
result(.failure(NetworkErrors.responseIsNotHTTP))
}
return
}
switch response.statusCode {
case 200...299:
if let data = data {
do {
let taskEntry = try JSONDecoder().decode(TaskEntry.self, from: data)
result(.success(taskEntry))
} catch {
result(.failure(error))
}
} else {
result(.failure(NetworkErrors.noDataProvided))
}
default:
if let error = error {
print(error.localizedDescription)
result(.failure(error))
} else {
result(.failure(NetworkErrors.unknown))
}
}
}.resume()
}
Additionally, you could pass this code to async/await form with a new function in iOS 15 or MacOS 12 (async/await it's a feature of swift 5.5, but the urlsession function that i've used it's only from ios 15 and macos 12向上):
@available(macOS 12.0, iOS 15.0, *)
func loadData() async throws -> Result<TaskEntry,Error> {
guard let url = URL(string: "myapi.php") else {
throw URLError(.badURL)
}
do {
let (data, urlResponse) = try await URLSession.shared.data(from: url, delegate: nil)
guard let response = urlResponse as? HTTPURLResponse else {
return .failure(NetworkErrors.responseIsNotHTTP)
}
switch response.statusCode {
case 200...299:
do {
let taskEntry = try JSONDecoder().decode(TaskEntry.self, from: data)
return .success(taskEntry)
} catch {
return .failure(error)
}
default:
return .failure(NetworkErrors.unknown)
}
} catch {
return .failure(error)
}
}
请投票,如果它澄清你。
祝你有美好的一天:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.