首页 文章

Swift JSONDecoder处理字典数组的字典

提问于
浏览
1

这是与swift上的JSONDecoder可编码功能相关的模型设计相关问题 .

我有以下JSON:

"author": {
    "name": "abc",
    "emailAddress": "abc@xyz.com",
    "id": 8665,
    "displayName": "A B C",
    "active": true,
    "slug": "abc",
    "type": "NORMAL",
    "links": {
        "self": [
                  {
                    "href": "some_href"
                  }
                ]
    }
 }

我试图使用新的swift 4 Codeable功能解码它 .

因此我创建了我的结构如下:

struct Author: Codeable {
    let name: String,
    let emailAddress: String,
    let id: String,
    let displayName: String,
    let active: String,
    let type: String,
    let links: [String: [Link]] 
}

struct Link: Codeable {
    let href: String
}

一旦我在这个json上运行JSONDecoder()解码,我就得到了上述格式的模型对象 . 但是,Author类中的links属性是作为字典获取的 . 现在要访问自我字段的值我需要大致做如下:

let selfLink = author.links["self"]
let href = selfLink[0].href

有没有更好的方法来建模结构,以便可以避免这种情况?

3 回答

  • 1

    是的,你可以通过添加一个这样的变量来做到这一点:

    struct Author: Codable {
        let name: String
        let emailAddress: String
        let id: String
        let displayName: String
        let active: String
        let type: String
        let links: [String: [Link]]
        var linkArr: [Link]? {
            return links["self"]
        }
    }
    

    并直接得到:

    author.linkArr[0].href
    
  • 1

    如果您确定每个作者总是至少有一个 href ,则可以添加计算属性:

    struct Author: Codable {
        let name: String
        let emailAddress: String
        let id: String
        let displayName: String
        let active: String
        let type: String
    
        let links: [String: [Link]]     
        var href: String {
            return links["self"]!.first!.href
        }
    }
    

    您也可以通过声明 private 来使外部无法访问 links .

  • 1

    在您的JSON中不常见或至少不恰当地命名的一件事是 links 属性实际上不是集合而是集合的包装对象 self . 这就是为什么我会坚持数据是什么,并将 links 属性映射到 linksWrapper (一个对象)和 selflinks (一个集合) .

    struct Author: Codable {
        let name: String
        let emailAddress: String
        let id: Int
        let displayName: String
        let active: Bool
        let slug: String
        let type: String
        let linksWrapper: LinksWrapper
    
        enum CodingKeys: String, CodingKey {
            case name, emailAddress, id, displayName, active, slug, type
            case linksWrapper = "links"
        }
    }
    
    struct LinksWrapper: Codable {
        let links: [Link]
    
        enum CodingKeys: String, CodingKey {
            case links = "self"
        }
    }
    
    struct Link: Codable {
        let href: String
    }
    

    然后,您可以按照JSON模型建议的相同层次顺序访问链接,但名称更有意义:

    let myLinks = author.linksWrapper.links.first
    

    但为方便起见,您可以将 readonly links 属性添加到 Author

    var links: [Link] {
        return linksWrapper.links
    }
    

    然后您可以直接访问链接:

    let myLinks = author.links
    

    但是,如果您有机会在JSON结构中修复此问题,那么请执行此操作 .

相关问题