簡體   English   中英

使用Decodable + Realm Swift解碼自定義JSON

[英]Decode custom JSON with Decodable + Realm Swift

從服務器上,我返回了一個很大的JSON,看起來像這樣:

{
  "id": "123",
  "status": "ok",
  "person": {
    "administration": {
      "name": "John"
    }
  },
  "company": {
    "name": "Test"
  }
}

我有一個結構:

struct Info: Decodable, Object {
  let id: String
  let status: String
  let personName: String
  let companyName: String
}

它符合可解碼協議,並且也是一個對象(領域實體)。 我的問題是:我可以通過某種方式解碼personName中人的名字嗎? 類似於person.administration.name。
我希望最終的Realm Object成為扁平對象,並且幾乎所有字段都是字符串。
是否應該為Person / Company創建單獨的結構而不將其設置為Realm Objects,而在解碼方法中將相應的值設置為“ personName”?

let personName: String = try container.decode((Person.Administration.name).self, forKey: .personName)

您可以簡單地使用containers通過Decodable解碼嵌套的數據,即

struct Info: Decodable {
    let id: String
    let status: String
    let personName: String
    let companyName: String

    enum CodingKeys: String, CodingKey {
        case id, status
        case person, administration
        case company
        case name
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        id = try values.decode(String.self, forKey: .id)
        status = try values.decode(String.self, forKey: .status)

        //Decoding personName
        let person = try values.nestedContainer(keyedBy: CodingKeys.self, forKey: .person)
        let administration = try person.nestedContainer(keyedBy: CodingKeys.self, forKey: .administration)
        personName = try administration.decode(String.self, forKey: .name)

        //Decoding companyName
        let company = try values.nestedContainer(keyedBy: CodingKeys.self, forKey: .company)
        companyName = try company.decode(String.self, forKey: .name)
    }
}

例:

我已經解碼了您在上面提供的JSON ,即

if let data = json.data(using: .utf8) {
    let info = try? JSONDecoder().decode(Info.self, from: data)
    print(info)
}

它給出的輸出是:

(id: "123", status: "ok", personName: "John", companyName: "Test")

您可以根據CodingKeys將所有不同級別的CodingKeys分開。 為了簡單起見,我將它們保持在同一級別。

建議:嘗試將optional typesCodable一起Codable 這是因為API響應可能是意外的。 而且,如果沒有得到任何預期的鍵值對,則在創建對象時可能最終得到nil

最好的做法是將要解析JSON的傳輸類型和代表存儲對象的類型分開。

但是,如果要使用此組合類型,則應執行以下操作:

struct Info: Decodable {
    let id: String
    let status: String
    let personName: String
    let companyName: String

    // JSON root keys
    private enum RootKeys: String, CodingKey {
        case id, status, person, company
    }
    // Keys for "person" nested "object"
    private enum PersonKeys: String, CodingKey {
        case administration
    }
    // Keys for "administration" and "company"
    private enum NamedKeys: String, CodingKey {
        case name
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: RootKeys.self)

        self.id = try container.decode(String.self, forKey: .id)
        self.status = try container.decode(String.self, forKey: .status)

        let personContainer = try container.nestedContainer(keyedBy: PersonKeys.self, forKey: .person)
        let administrationContainer = try personContainer.nestedContainer(keyedBy: NamedKeys.self, forKey: .administration)
        self.personName = try administrationContainer.decode(String.self, forKey: .name)

        let companyContainer = try container.nestedContainer(keyedBy: NamedKeys.self, forKey: .company)
        self.companyName = try companyContainer.decode(String.self, forKey: .name)
    }
}

為了某種類型的安全性,我將密鑰分為三種不同的CodingKey類型,以防止意外混淆。

暫無
暫無

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

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