2

这是我正在使用的代码,

struct CreatePostResponseModel : Codable{
    var transcodeId:String?
    var id:String = ""
    enum TopLevelCodingKeys: String, CodingKey {
        case _transcode = "_transcode"
        case _transcoder = "_transcoder"
    }
    enum CodingKeys:String, CodingKey{
        case id = "_id"
    }
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: TopLevelCodingKeys.self)
        if let transcodeId = try container.decodeIfPresent(String.self, forKey: ._transcode) {
            self.transcodeId = transcodeId
        }else if let transcodeId = try container.decodeIfPresent(String.self, forKey: ._transcoder) {
            self.transcodeId = transcodeId
        }

    }
}

在这里,transcodeId_transcode或决定_transcoder。但我希望id和其余的键(不包括在这里)被自动解码。我该怎么做 ?

4

3 回答 3

2

init(from:)Codable类型中实现后,您需要手动解析所有键。

struct CreatePostResponseModel: Decodable {
    var transcodeId: String?
    var id: String

    enum CodingKeys:String, CodingKey{
        case id, transcode, transcoder
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decodeIfPresent(String.self, forKey: .id) ?? ""
        if let transcodeId = try container.decodeIfPresent(String.self, forKey: .transcode) {
            self.transcodeId = transcodeId
        } else if let transcodeId = try container.decodeIfPresent(String.self, forKey: .transcoder) {
            self.transcodeId = transcodeId
        }
    }
}

在上面的代码中,

  1. 如果您只想解码JSON,则无需使用Codable. 使用Decodable就足够了。
  2. 在这里使用多个enumsforCodingKey似乎是不必要的。您可以使用单个enum CodingKeys.
  3. 如果属性名键名rawValue完全匹配,则无需caseenum CodingKeys. 因此,没有"_transcode"and "_transcoder" rawValuesin 的要求TopLevelCodingKeys

除此之外,您还可以使用keyDecodingStrategyas.convertFromSnakeCase来处理下划线表示法(蛇形表示法),即

do {
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase //here.....
    let model = try decoder.decode(CreatePostResponseModel.self, from: data)
    print(model)
} catch {
    print(error)
}

因此,您无需显式处理所有蛇形钥匙。它将由JSONDecoder它自己处理。

于 2019-07-26T09:09:37.373 回答
1

编译器生成init(from:)的是全有或全无。您不能让它解码某些键并“手动”解码其他键。

使用编译器生成的一种方法init(from:)是提供struct 两个可能的编码属性,并创建transcodeId一个计算属性:

struct CreatePostResponseModel: Codable {
    var transcodeId: String? {
        get { _transcode ?? _transcoder }
        set { _transcode = newValue; _transcoder = nil }
    }

    var _transcode: String? = nil
    var _transcoder: String? = nil

    var id: String = “”
    // other properties
}
于 2019-11-14T08:04:42.830 回答
1

无论您想为一个变量添加多个键,这对您来说都是一种很好的解决方案:

var transcodeId:String?

public init(from decoder: Decoder) throws {

    do {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        transcodeId =  container.getValueFromAvailableKey(codingKeys: [CodingKeys._transcoder,CodingKeys._transcode])
    } catch {
        print("Error reading config file: \(error.localizedDescription)")
    }
}

extension KeyedDecodingContainerProtocol{

    func getValueFromAvailableKey(codingKeys:[CodingKey])-> String?{
         for key in codingKeys{
             for keyPath in self.allKeys{
                 if key.stringValue == keyPath.stringValue{
                    do{ 
                        return try self.decodeIfPresent(String.self, forKey: keyPath)
                    } catch {
                        return nil
                    }
                }
            }
        }
        return nil
    }
}

希望能帮助到你。

于 2019-11-14T07:23:57.760 回答