简体   繁体   English

iOS:如何访问和使用来自 REST Z2B85CB3D5FCE6D1C89DD2B392E48 的 API 响应数据

[英]iOS: How to access and use API response data from REST SwiftUi

firstly I am really new to iOS development and Swift (2 weeks coming here from PHP:))首先,我对 iOS 开发和 Swift 真的很陌生(从 PHP 来这里两周 :))

I am creating a application that has a callout to my very simple api.我正在创建一个应用程序,它对我非常简单的 api 进行了标注。 I am using the below code but an unable to access the 'if let response' part of the code and unable to get the value of 'Comments' from the returned data from api.我正在使用下面的代码,但无法访问代码的“if let response”部分,也无法从 api 返回的数据中获取“Comments”的值。 Wondering if anyone can help on this.想知道是否有人可以提供帮助。

The data come back fine as数据恢复正常

//Print out fine
print(str)

will print my response of {"Comments":"success"}将打印我对{"Comments":"success"}的回复

so just wondering how I can properly use this data and check if success etc所以只是想知道如何正确使用这些数据并检查是否成功等

Thanks谢谢


        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
    }

With the description provided by you, the JSON that returns your API is the following:根据您提供的描述,返回您的 API 的 JSON 如下:

{ 
    "Comments": "success"
}

Is that right?那正确吗?

If it is, this part of your code如果是,这部分代码

if let response = try? JSONDecoder().decode([TaskEntry].self, from: data)

Marks that you are decoding data fetched from your app as Array.标记您将从应用程序获取的数据解码为数组。 You specify an array of TaskEntry right here [TaskEntry].self for your data that's not true, you need to decode json with try? JSONDecoder().decode(TaskEntry.self, from: data)您在此处[TaskEntry].self为您的数据指定了一个 TaskEntry 数组,这是不正确的,您需要try? JSONDecoder().decode(TaskEntry.self, from: data) try? JSONDecoder().decode(TaskEntry.self, from: data)

If you hope for an array your api must to return something like this如果你希望一个数组你的 api 必须返回这样的东西

[
  {
    "Comments": "success"
  }
]

For check if it is right with status code I provide a restructuration of your code explained.为了检查状态码是否正确,我提供了对您的代码进行解释的重构。

First, protocol Codable it's used to decode and encode data with Encoders and Decoders.首先,Codable 协议用于使用 Encoders 和 Decoders 对数据进行解码和编码。 In that case, you are working with JSONs so you use JSONDecoder to decode data.在这种情况下,您正在使用 JSON,因此您使用 JSONDecoder 来解码数据。 You only need decode, so with Decodable protocol It's enough.你只需要解码,所以使用 Decodable 协议就足够了。 You don't need to mark Comments with public, because you are working with TaskEntry in your project, so by default (no specified) It's internal.您不需要将 Comments 标记为 public,因为您在项目中使用 TaskEntry,所以默认情况下(未指定)它是内部的。 Moreover you don't need var, because, you are not making changes of the property.此外,您不需要 var,因为您没有更改属性。 Also, properties as standard starts with lowercase, so you can use CodingKeys to keep a quality code standard.此外,作为标准的属性以小写字母开头,因此您可以使用 CodingKeys 来保持质量代码标准。

You can check it in Apple Developer site您可以在Apple Developer 网站中查看

struct TaskEntry: Decodable {
    let comments: String

    enum CodingKeys: String, CodingKey {
        case comments = "Comments"
    }
}

Then, you should to think about your Api errors and defined it.然后,您应该考虑您的 Api 错误并对其进行定义。 I give you an example:我给你举个例子:

enum NetworkErrors: Error {
    case responseIsNotHTTP
    case noDataProvided
    case unknown
}

Your load function, should to communicate to external class or struct the TaskEntry or the error.您的负载 function 应该与外部 class 通信或构造 TaskEntry 或错误。 You could use a closure with a Result.您可以使用带有 Result 的闭包。 Please check the link Hacking with Swift .请检查链接Hacking with Swift This has two cases with associated values, failure and success.这有两种具有关联值的案例,失败和成功。

Further the response of your UrlSessionTask need to be cast to HTTPURLResponse to get the response http status code.此外,您的 UrlSessionTask 的响应需要转换为 HTTPURLResponse 以获取响应 http 状态代码。 I provide an example of that with your code.我用你的代码提供了一个例子。

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 to up): 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)
    }
}

Please, vote up if it's clarify you.请投票,如果它澄清你。

Have a good day:)祝你有美好的一天:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM