簡體   English   中英

如何手動解碼選定的鍵並使用 swift Decodable 自動解碼?

[英]How to Decode selected keys manually and rest with the automatic decoding with swift Decodable?

這是我正在使用的代碼,

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和其余鍵(不包括在此處)。 我該怎么做 ?

Codable類型中實現init(from:) ,您需要手動解析所有鍵。

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. 在這里似乎沒有必要為CodingKey使用多個enums 您可以使用單個enum CodingKeys
  3. 如果屬性名密鑰名是完全匹配的,就沒有必要明確指定rawValue是的caseenum CodingKeys 因此, TopLevelCodingKeys不需要"_transcode""_transcoder" rawValues

除此之外,您可以使用keyDecodingStrategy作為.convertFromSnakeCase來處理下划線符號(蛇大小寫符號),即

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

因此,您不需要顯式處理所有蛇形大小寫的鍵 它將由JSONDecoder自行處理。

無論您在何處都可以為一個變量添加多個鍵,這對您來說都是不錯的解決方案之一:

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
    }
}

希望能幫助到你。

編譯器生成的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
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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