簡體   English   中英

當使用 Swift

[英]How to map a single value from a JSON dictionary to a property when using Swift Decodable

我有一個看起來像這樣的 JSON object:

{
    "name": "Acid Arrow",
    "school": {
        "name": "Evocation",
        "url": "http://www.dnd5eapi.co/api/magic-schools/5"
    }
}

我想 Swift 中的 model 如下:

struct Spell: Decodeable {
    let name: String
    let school: MagicSchool
}

enum DnDMagicSchool: String {
    case abjuration = "Abjuration"
    case abjuration = "Abjuration" 
    case conjuration = "Conjuration" 
    case divination = "Divination"   
    case enchantment = "Enchantment"    
    case evocation = "Evocation"   
    case illusion = "Illusion"   
    case necromancy = "Necromancy"  
    case transmutation = "Transmutation"   
}

我能找到將 JSON school字典減少到單個枚舉值的唯一方法是通過提供一個看起來像這樣的自定義init(from decoder: Decoder)初始化程序來實現整個Decodeable

extension Spell: Decodeable {
    init(from decoder: Decoder) {
        let values = try decoder.container(keyedBy: CodingKeys.self)

        // manually map to the spell name
        name = try values.decode(String.self, forKey: .name)

        // manually decode **school** into a dictionary
        let jsonSchool = try values.decode(Dictionary<String,String>.self, forKey: .school)

        // extract the "name" property from the dict and assign it as `DnDMagicSchool` enum
        school = DnDMagicSchool(rawValue: jsonSchool["name"])

    }
}

但它不喜歡它,因為Spell.school的鍵類型存在類型沖突

我是否試圖以錯誤的方式做到這一點? 有沒有更簡單的方法可以將復雜類型轉換為基本類型或在映射中指定路徑?

使用init(from decoder: Decoder) throws {初始化程序是處理這種情況的適當方式。

school實體打交道可能有不同的方式。 我更喜歡將其解碼為結構以獲得類型安全。

正如評論中指出的那樣,您提供的代碼充滿了拼寫錯誤。 在清理完這些之后,這只是一個可選的蜜蜂分配給非可選字段的情況。

struct Spell: Decodable {
    let name: String
    let school: MagicSchool
}

enum MagicSchool: String {
    case abjuration = "Abjuration"
    case conjuration = "Conjuration"
    case divination = "Divination"
    case enchantment = "Enchantment"
    case evocation = "Evocation"
    case illusion = "Illusion"
    case necromancy = "Necromancy"
    case transmutation = "Transmutation"
}

extension Spell {
    
    struct InternalSchool: Decodable{
        let name: String
        let url: String
    }
    
    enum CodingKeys: CodingKey{
        case name, school
    }
    
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)

        // manually map to the spell name
        name = try values.decode(String.self, forKey: .name)

        // manually decode **school** into the custom type
        let school = try values.decode(InternalSchool.self, forKey: .school)

        // check if you can create an enum from the given string and throw appropriate error
        guard let schoolEnum = MagicSchool(rawValue: school.name) else{
            throw DecodingError.dataCorrupted(.init(codingPath: [CodingKeys.school], debugDescription: "school has unknown value"))
        }
        // assign enum
        self.school = schoolEnum
    }
}

暫無
暫無

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

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