декодирование массива JSON или словаря ошибки swift - PullRequest
0 голосов
/ 05 мая 2018

Я впервые делаю снимок в Codable / Decodable, и я хотел бы декодировать JSON. Я пытаюсь получить доступ к ключам «имя» и «описание» в массиве событий. Ниже приведен фрагмент JSON - я получаю эту ошибку в моем коде

"Ожидается декодирование словаря, но вместо этого найден массив."

"pagination": {

    "page_number": 1, 
    "page_size": 50, 
    "continuation": "eyJwYWdlIjogMn0", 
    "has_more_items": true
}, 

"events": [
    {
        "name": {
            "text": "Genesis Part 4", 
            "html": "Genesis Part 4"
        }, 

        "description": {
            "text": "Wednesday, June 6-June 27, 2018\n12:00-2:15 PM, Eastern Time\n\u00a0\nCOED\n\u00a0\nBible Study Leader:\u00a0Nicki Cornett\n\u00a0\nContact:NickiCornett@gmail.com\n\u00a0\nGenesis Part 4 -\u00a0Wrestling with God - A Study on Isaac, Jacob, and Esau- Precept Workbook (NASB)\n\u00a0\nGod renews His covenant promise with Abraham through Isaac and Jacob.

Вот как я приступил к декодированию - (ПРИМЕЧАНИЕ - «описание» еще не здесь, потому что у меня возникла проблема с обработкой массива событий для доступа к имени и описанию

struct Eventbrite: Decodable {

 private enum CodingKeys : String, CodingKey { case events = "events",  name = "name"}
    let events: [String:[String]]
    let name: [String:[String]]

}

   URLSession.shared.dataTask(with: url) { (data, response, error) in

        guard let data = data else {return}

        do {

        let eventbriteData = try JSONDecoder().decode(Eventbrite.self, from: data)


            print(eventbriteData.name)

Ответы [ 2 ]

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

Правильно, поэтому Decodable на самом деле довольно умен, так как вам не нужно писать код для самостоятельного декодирования. Вам просто нужно убедиться, что вы соответствуете структуре JSON (и создаете структуры, которые также соответствуют Decodable для любых вложенных объектов). Другими словами, вместо использования переменных в качестве словарей сделайте их собственной декодируемой структурой.

Так, например:

struct EventBrite: Decodable {
    let pagination: Pagination
    let events: [Event]
}

struct Pagination: Decodable {
    let page_number: Int
    let page_size: Int
    let continuation: String
    let has_more_items: Bool
}

struct Event: Decodable { 
     let name: EventName
     let description: EventDescription
}

struct EventName: Decodable {
    let name: String
    let html: String
}

и т.д ...

Здесь важно еще кое-что, если не гарантируется, что ключ или свойство будет возвращено (например, скажем, что EventName не всегда имеет HTML-значение, возвращаемое с сервера, вы можете легко пометить это значение). как необязательный. Так что-то вроде:

struct EventName: Decodable {
    let name: String
    let html: String?
}

Еще одно замечание: вы действительно испортили объявления типа словаря. Вы заметите, что event на самом деле имеет тип [String: [String: String]], поскольку ключ является строкой, а значения, кажется, всегда словаря. И зовут [String: String]. Это не то, что вы записали, как в первоначальном вопросе.

Когда значения могут отличаться, как при разбивке на страницы, вам нужно сделать что-то вроде [String: Any], так что будьте осторожны с этим.

ОДНАКО Подход, который я предложил, я думаю, лучше, чем иметь свойства как словари. Во-первых, вам не нужно беспокоиться об объявлении типа словаря (в котором вы допустили несколько небольших ошибок). Но что более важно, когда каждый словарь становится своей собственной четко определенной структурой, и вам не нужно беспокоиться о запоминании или поиске ключей. Синтаксис точки / автозаполнение автоматически подскажет вам, что может быть! (И не приведение, когда ваше значение имеет тип Any или AnyObject!)

Также определенно используйте структуры для всего этого, поскольку я однажды оценил производительность и измерил эффективность структур на порядок в миллионы раз эффективнее, чем классы. Просто к вашему сведению.

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

name явно не входит в область действия pagination и events (обратите внимание на {}) и является обычным [String:String] словарем, который можно декодировать в другую структуру.

Расшифруйте это (так как description не завершено, я пропустил это), вам не нужно CodingKeys:

struct Eventbrite: Decodable {
    let events: [Event]
}

struct Event: Decodable {
    let name: Name
    // let description: [String:String]
}

struct Name : Decodable {
    let text, html : String
}
...