无法将类型"Codable"(也称为"Decodable& Encodable")的值转换为预期的参数类型"T.Type"

无法将类型

问题描述:

我正在处理一个处理JSON解析的小型结构.到目前为止,一切正常,除了我要传递自定义结构作为要在 JSONDecoder().decode(type.self,from:data)的解码中使用的结构之外,但这是抛出以下错误:

I'm working on a small struct that handles the parsing of JSON. Up until now it is all working except I am wanting to pass a custom struct as a structure to use on the decode in JSONDecoder().decode(type.self, from: data) but this is throwing the following error:

无法将类型"Codable"(也称为"Decodable& Encodable")的值转换为预期的参数类型"T.Type"

Cannot convert value of type 'Codable' (aka 'Decodable & Encodable') to expected argument type 'T.Type'

private func parseJson(data: Data, type: Codable) -> Codable? {
    do {
        let decoded = try JSONDecoder().decode(type.self, from: data)
        
        return decoded
    } catch {
        print("JSON decode error: \(error.localizedDescription)")
    }
    
    return nil
}

是否可以将结构体传递给此方法以用作 decode()函数的类型?如果我直接设置要传递给该函数的类型,则该代码将按预期工作,仅当我尝试将其传递时才会出错.

Is there a way that I can pass a struct into this method to use as the type for the decode() function? If I directly set the type I'm trying to pass into the function on the decode() function the code works as expected, it only errors out when I attempt to pass it in.

您需要的是通用方法:

private func parseJson<T: Decodable>(data: Data, type: T.Type) -> T? {
    do {
        return try JSONDecoder().decode(type.self, from: data)
    } catch {
        print("JSON decode error:", error)
        return nil
    }
}

您还可以省略类型并显式设置结果对象的类型:

You can also omit the type and explicitly set the type of the resulting object:

private func parseJson<T: Decodable>(data: Data) -> T? {
    do {
        return try JSONDecoder().decode(T.self, from: data)
    } catch {
        print("JSON decode error:", error)
        return nil
    }
}


游乐场测试:


Playground testing:

struct User: Codable {
    let id: Int
    let name: String
}
let user: User = .init(id: 2, name: "abc")
let userData = try! JSONEncoder().encode(user)

let decodedUser: User = parseJson(data: userData)!
decodedUser.name  // "abc"

注意:我返回的是可选类型,但绝对应该使方法抛出并返回非可选的类型,如下面在我扩展数据的地方所见:

Note: I am returning optional types but you should definitely make your methods throw and return a non optional as you can see below where I am extending Data:

extension Data {
    func decodedObject<T: Decodable>() throws -> T {
        try JSONDecoder().decode(T.self, from: self)
    }
}


do {
    let decodedUser: User = try userData.decodedObject()
    print(decodedUser.name)  // "abc"
} catch {
    print(error)
}