SWIFTUI - Json 总是解码 returns keyNotFound

SWIFTUI - Json decoding always returns keyNotFound

当我尝试在 SwiftUI 中解码我的 JSON 时,它总是给出错误:

keyNotFound(CodingKeys(stringValue: "is_paid", intValue: nil)

Double 等某些值似乎确实有效,但其他类型似乎会出现此类错误。我一直在寻找这个答案超过 2 天,我为此感到很崩溃。

型号

struct Invoices: Decodable, Hashable, Identifiable {
    let id: Int
    let is_paid: Int
    let total: Double
    let invoice_id: String
}

不知何故 idtotal 给出了正确的值:

success([KlantenTest.InvoiceTest(id: 22, total: 30.0), KlantenTest.InvoiceTest(id: 26, total: 29.9959), KlantenTest.InvoiceTest(id: 28, total: 363.0), KlantenTest.InvoiceTest(id: 31, total: 240.1608), KlantenTest.InvoiceTest(id: 32, total: 29.9959)])

函数

func getCategorByAPI() -> Void {
    let url = URL(string: "\(self.Api_URL)/api/v1/webhook/invoices/\(self.Api_token)/\(self.UserToken ?? self.Default)")!
    
    var request  = URLRequest(url: url)
    
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")
    request.setValue("Bearer \(self.Token ?? "")", forHTTPHeaderField: "Authorization")

    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    URLSession.shared.jsonDecodableTask(with: request, decoder: decoder) { (result: Result<[InvoiceTest], Error>) in
        
        print(result)
        switch result {
            case .success(let person):
                print("InvoiceID: \(person)")
            case .failure(let error):
                print(error)
        }
    }.resume()
}

分机

enum URLError: Error {
    case noData, decodingError
}

extension URLSession {
    /// A type safe URL loader that either completes with success value or error with Error
    func jsonDecodableTask<T: Decodable>(with url: URLRequest, decoder: JSONDecoder = JSONDecoder(), completion: @escaping (Result<T, Error>) -> Void) -> URLSessionDataTask {
       self.dataTask(with: url) { (data, response, error) in
            DispatchQueue.main.async {
                guard error == nil else {
                    completion(.failure(error!))
                    return
                }
                guard let data = data, let _ = response else {
                    completion(.failure(URLError.noData))
                    return
                }
                do {
                    let decoded = try decoder.decode(T.self, from: data)
                    completion(.success(decoded))
                } catch  {
                    completion(.failure(error))
                }
            }
        }
    }

    func jsonDecodableTask<T: Decodable>(with url: URL, decoder: JSONDecoder = JSONDecoder(), completion: @escaping (Result<T, Error>) -> Void) -> URLSessionDataTask {
       self.jsonDecodableTask(with: URLRequest(url: url), decoder: decoder, completion: completion)
    }
}

JSON

[
    {
        "id": 28,
        "invoice_id": "20210126075159",
        "total": 363,
        "is_paid": 1,
    },
    {
        "id": 31,
        "invoice_id": "20210126075161",
        "total": 240.1608,
        "is_paid": 1,
    },
    {
        "id": 32,
        "invoice_id": "20210126075162",
        "total": 29.9959,
        "is_paid": 1,
    }
]

如您所见,这些值实际上在那里,所以我不明白错误是从哪里来的,因为当我尝试下面的函数时,它确实适用于相同的模型 Invoices

 let Url = URL(string: "\(self.Api_URL)/api/v1/webhook/invoices/\(self.Api_token)/\(self.UserToken ?? self.Default)")!

    var request = URLRequest(url: Url)
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")
    request.setValue("Bearer \(self.Token ?? "")", forHTTPHeaderField: "Authorization")
    
    URLSession.shared.dataTask(with: request) { (data, res, err) in
        //check response status and err
        guard let data = data else { return }
        
        do {
            let invoice = try JSONDecoder().decode([Invoices].self, from: data)
            self.invoices = invoice
            
        } catch {
            print("Failed to decode: \(error)")
        }
    }.resume()

PS。我也试过通过[GetInvoices]

调用
struct GetInvoices: Decodable {
    let invoices: [Invoices]
}

但是那连id或者Invoices能找到的total都找不到,所以没用.

使用的代码来自:

您的问题在:.convertFromSnakeCase

如参考文献所述:https://developer.apple.com/documentation/foundation/jsondecoder/keydecodingstrategy/convertfromsnakecase

is_paid 正在被解码为 isPaid,与 invoice_id 相同。