Swift JSONDecoder处理字典数组字典

时间:2018-05-13 19:16:42

标签: swift jsondecoder

这是与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 个答案:

答案 0 :(得分: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 :(得分:1)

如果您确定每位作者总是至少有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
    }
}

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

答案 2 :(得分: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结构中修复此问题,那么请执行此操作。