簡體   English   中英

iOS:如何訪問和使用來自 REST Z2B85CB3D5FCE6D1C89DD2B392E48 的 API 響應數據

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM