【问题标题】:How to return class type for decoding codable in swift如何返回类类型以快速解码可编码
【发布时间】:2021-02-17 10:35:35
【问题描述】:

我正在尝试创建一个服务类,该服务类也将具有相应 api 的解码类类型

import UIKit

struct LoginResponse: Codable {
    var action: String
    var result: String
    var key: String
}

struct LogoutResponse: Codable {
    var action: String
    var result: String
}

enum Api {
    case login
    case logout
    
    var backingType: Codable {
        switch self {
        case .login:
            return LoginResponse.self as! Codable
        case .logout:
            return LogoutResponse.self as! Codable
        }
    }
}
let loginResponse = LoginResponse(action: "login", result: "result", key: "key")
let loginData = try! JSONEncoder().encode(loginResponse)

let decodedData = try! JSONDecoder().decode(Api.login.backingType, from: loginData)

我得到的错误是 ->

**无法将类型“Codable.Type”(又名“(Decodable & Encodable).Type”)的值转换为预期的参数类型“T.Type”

无法推断通用参数“T”。**

我也尝试过使用泛型

import UIKit

struct LoginResponse: Codable {
    var action: String
    var result: String
    var key: String
}

struct LogoutResponse: Codable {
    var action: String
    var result: String
}

enum Api<T: Codable> {
    case login
    case logout
    
    var backingType: Codable.Type {
        switch self {
        case .login:
            return LoginResponse.self
        case .logout:
            return LogoutResponse.self
        }
    }
    
    var genericBackingType: T.Type {
        switch self {
        case .login:
            return LoginResponse.self as! T.Type
        case .logout:
            return LogoutResponse.self as! T.Type
        }
    }
}
let loginResponse = LoginResponse(action: "login", result: "result", key: "key")
let loginData = try! JSONEncoder().encode(loginResponse)
let decodedData = try! JSONDecoder().decode(Api.login.backingType as! Codable.Type, from: loginData)

请指点我一个合适的方向

【问题讨论】:

  • 您希望decodedData 的类型是什么?
  • @Sweeper 来自 backingType 变量的结构对象。如果通过登录,则它应该是 LoginResponse 类型,否则是 LogoutResponse。

标签: swift generics codable


【解决方案1】:

在这两种尝试中,要解码的类型必须是具体类型,不能是协议。


在这种情况下,最合适的解决方案是使用关联类型的枚举

enum Api : Decodable {
    case login(LoginResponse)
    case logout(LogoutResponse)
    
    private enum CodingKeys : String, CodingKey { case action, result, key }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let action = try container.decode(String.self, forKey: .action)
        let result = try container.decode(String.self, forKey: .result)
        switch action {
            case "login":
                let key = try container.decode(String.self, forKey: .key)
                self = .login(LoginResponse(action: action, result: result, key: key))
            case "logout":
                self = .logout(LogoutResponse(action: action, result: result))
            default : throw DecodingError.dataCorruptedError(forKey: .action, in: container, debugDescription: "Invalid action: \(action)")
        }
    }
}

它解码action 键并根据值返回具有相关响应类型的适当大小写。

结构可以相同,如果在现实生活中结构永远不会被编码,您甚至可以省略 action 成员。如果是这样,您可以进一步省略 LogoutResponse 结构并在 logout 案例中为 result 使用关联类型 String

struct LoginResponse : Codable {
    let action: String
    let result: String
    let key: String
}

struct LogoutResponse : Codable {
    let action: String
    let result: String
}

而解码的方法是

let loginResponse = LoginResponse(action: "login", result: "result", key: "key")
let loginData = try! JSONEncoder().encode(loginResponse)

let decodedApi = try! JSONDecoder().decode(Api.self, from: loginData)
switch decodedApi {
    case .login(let response): print(response)
    case .logout(let response): print(response)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    • 2018-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多