Swift JSONDecoder обрабатывает словарь из массива словарей - PullRequest
0 голосов
/ 13 мая 2018

Это вопрос, связанный с дизайном модели, связанный с кодируемой функциональностью JSONDecoder на swift.

У меня есть следующий 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
} 

Как только я запускаю JSONDecoder (). Decode для этого json, я получаю объекты модели в вышеуказанном формате. Однако свойство links в классе Author получается в виде словаря. И теперь, чтобы получить доступ к значению собственного поля, мне нужно примерно сделать следующее:

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

Есть ли лучший способ смоделировать структуру, чтобы этого можно было избежать?

Ответы [ 3 ]

0 голосов
/ 14 мая 2018

Если вы уверены, что у каждого автора всегда есть хотя бы 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.

0 голосов
/ 14 мая 2018

Одна вещь, которая не совсем обычна или, по крайней мере, неправильно названа в вашем JSON, заключается в том, что свойство links на самом деле является не коллекцией, а объектом-оболочкой для коллекции self. Вот почему я остаюсь верным данным и сопоставляю свойство links с именами linksWrapper (объект) и self с links (коллекция).

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, сделайте это вместо этого.

0 голосов
/ 13 мая 2018

Да, вы можете сделать это, добавив еще одну переменную:

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