Свойство Codable настраиваемого типа класса не может инициализировать свои собственные свойства из JSON

Мой Джсон:

    {  
   "message":"OK",
   "response":[  
      {  
         "article_id":"201802062200722818",
         "lead":"Poliisi vapautti naisen ja otti miehen kiinni. Satakunnan käräjäoikeus vangitsi miehen tiistaina.",
         "headline":"Poliisi epäilee: 19-vuotias raumalaismies piti alaikäistä naista mökillä vankina",
         "title":"Poliisi epäilee: 19-vuotias raumalaismies piti alaikäistä naista mökillä vankina",
         "service_name":"iltalehti",
         "main_image_name":"cae51c694cc7f31257290ff96489f3cf852329a887509621b29a27fbaa0f8894.jpg",
         "category":{  
            "category_name":"kotimaa",
            "description":"Kotimaan uutiset",
            "parent_category":{  
               "category_name":"uutiset",
               "description":"Uutiset",
               "parent_category":null
            }
         },
         "main_image_urls":{  
            "default":"https://img.ilcdn.fi/PcWFp0weItXN2WAWKBXCO_H2VsQ=/510x/img-s3.ilcdn.fi/cae51c694cc7f31257290ff96489f3cf852329a887509621b29a27fbaa0f8894.jpg",
            "size30":"https://img.ilcdn.fi/_LNHr84u93ntg3tX37oHyGBlRNA=/30x/img-s3.ilcdn.fi/cae51c694cc7f31257290ff96489f3cf852329a887509621b29a27fbaa0f8894.jpg",
            "size98":"https://img.ilcdn.fi/r624bQFqaJ3xqrMScif38JH6SBM=/98x/img-s3.ilcdn.fi/cae51c694cc7f31257290ff96489f3cf852329a887509621b29a27fbaa0f8894.jpg",
            "size138":"https://img.ilcdn.fi/dyemZCdMpjAFTnnD5JiYLh3WGJI=/138x/img-s3.ilcdn.fi/cae51c694cc7f31257290ff96489f3cf852329a887509621b29a27fbaa0f8894.jpg",
            "size244":"https://img.ilcdn.fi/2AiJpLa4oLxEDE0jL_LazhOiTMM=/244x/img-s3.ilcdn.fi/cae51c694cc7f31257290ff96489f3cf852329a887509621b29a27fbaa0f8894.jpg",
            "size293":"https://img.ilcdn.fi/iyAZVQ0ufAHrX2inGCiE9QPQjMU=/293x/img-s3.ilcdn.fi/cae51c694cc7f31257290ff96489f3cf852329a887509621b29a27fbaa0f8894.jpg",
            "size310":"https://img.ilcdn.fi/XGmL7EEqo0OR5Vzvbel1hSeTmHI=/310x/img-s3.ilcdn.fi/cae51c694cc7f31257290ff96489f3cf852329a887509621b29a27fbaa0f8894.jpg",
            "size510":"https://img.ilcdn.fi/PcWFp0weItXN2WAWKBXCO_H2VsQ=/510x/img-s3.ilcdn.fi/cae51c694cc7f31257290ff96489f3cf852329a887509621b29a27fbaa0f8894.jpg",
            "size820":"https://img.ilcdn.fi/N-XV5ZqQASGpvUe-3DAcq4i1928=/820x/img-s3.ilcdn.fi/cae51c694cc7f31257290ff96489f3cf852329a887509621b29a27fbaa0f8894.jpg",
            "size1024":"https://img.ilcdn.fi/J5Cm5P2SJMNymHza7s3LdEEvKLg=/1024x/img-s3.ilcdn.fi/cae51c694cc7f31257290ff96489f3cf852329a887509621b29a27fbaa0f8894.jpg"
         },
         "published_at":"2018-02-06T10:42:40+02:00",
         "updated_at":null
      }
   ]
}

мой Codable Модельные классы

Articles.swift

import Foundation
struct Articles : Codable {
    let message : String?
    let response : [Article]?

    enum CodingKeys: String, CodingKey {

        case message = "message"
        case response = "response"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        message = try values.decodeIfPresent(String.self, forKey: .message)
        response = try values.decodeIfPresent([Article].self, forKey: .response)
    }

}

Article.swift

import Foundation
struct Article : Codable {
    let article_id : String?
    let lead : String?
    let headline : String?
    let title : String?
    let service_name : String?
    let main_image_name : String?
    let category : Category?
    let main_image_urls : Main_image_urls?
    let published_at : String?
    let updated_at : String?

    enum CodingKeys: String, CodingKey {

        case article_id = "article_id"
        case lead = "lead"
        case headline = "headline"
        case title = "title"
        case service_name = "service_name"
        case main_image_name = "main_image_name"
        case category
        case main_image_urls
        case published_at = "published_at"
        case updated_at = "updated_at"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        article_id = try values.decodeIfPresent(String.self, forKey: .article_id)
        lead = try values.decodeIfPresent(String.self, forKey: .lead)
        headline = try values.decodeIfPresent(String.self, forKey: .headline)
        title = try values.decodeIfPresent(String.self, forKey: .title)
        service_name = try values.decodeIfPresent(String.self, forKey: .service_name)
        main_image_name = try values.decodeIfPresent(String.self, forKey: .main_image_name)
        category = try Category(from: decoder)
        main_image_urls = try Main_image_urls(from: decoder)
        published_at = try values.decodeIfPresent(String.self, forKey: .published_at)
        updated_at = try values.decodeIfPresent(String.self, forKey: .updated_at)
    }

}

Category.swift

import Foundation
struct Category : Codable {
    let category_name : String?
    let description : String?
    let parent_category : Parent_category?

    enum CodingKeys: String, CodingKey {

        case category_name = "category_name"
        case description = "description"
        case parent_category
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        category_name = try values.decodeIfPresent(String.self, forKey: .category_name)
        description = try values.decodeIfPresent(String.self, forKey: .description)
        parent_category = try Parent_category(from: decoder)
    }

}

Parent_category.swift

import Foundation
struct Parent_category : Codable {
    let category_name : String?
    let description : String?
    let parent_category : String?

    enum CodingKeys: String, CodingKey {

        case category_name = "category_name"
        case description = "description"
        case parent_category = "parent_category"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        category_name = try values.decodeIfPresent(String.self, forKey: .category_name)
        description = try values.decodeIfPresent(String.self, forKey: .description)
        parent_category = try values.decodeIfPresent(String.self, forKey: .parent_category)
    }

}

Проблема:

Я пытаюсь использовать Codable протокол для инициализации моей модели классов из JSON. Он хорошо работает для собственных типов данных (String, Int и т. Д.), Но если структура содержит объект свойства пользовательского типа, он не инициализирует свойства этой пользовательской структуры (класса).

Пример: Category это объект пользовательского типа в Article структура. Каждый пользовательский класс отвечает за инициализацию своих свойств, подтверждает Codable протокол и имеет свой собственный init(from decoder: Decoder) метод.

Но почему-то category и другие пользовательские типы не могут инициализировать свои собственные свойства (например, category_name = nil в Category класс, и то же самое происходит с Parent_category а также Main_image_urls) и я получаю следующий результат: (некоторые значения равны нулю)

Консольный журнал на xcode

po article

▿ Optional<Article>
  ▿ some : Article
    ▿ article_id : Optional<String>
      - some : "201802062200722818"
    ▿ lead : Optional<String>
      - some : "Poliisi vapautti naisen ja otti miehen kiinni. Satakunnan käräjäoikeus vangitsi miehen tiistaina."
    ▿ headline : Optional<String>
      - some : "Poliisi epäilee: 19-vuotias raumalaismies piti alaikäistä naista mökillä vankina"
    ▿ title : Optional<String>
      - some : "Poliisi epäilee: 19-vuotias raumalaismies piti alaikäistä naista mökillä vankina"
    ▿ service_name : Optional<String>
      - some : "iltalehti"
    ▿ main_image_name : Optional<String>
      - some : "cae51c694cc7f31257290ff96489f3cf852329a887509621b29a27fbaa0f8894.jpg"
    ▿ category : Optional<Category>
      ▿ some : Category
        - category_name : nil
        - description : nil
        ▿ parent_category : Optional<Parent_category>
          ▿ some : Parent_category
            - category_name : nil
            - description : nil
            - parent_category : nil
    ▿ main_image_urls : Optional<Main_image_urls>
      ▿ some : Main_image_urls
        - default : nil
        - size30 : nil
        - size98 : nil
        - size138 : nil
        - size244 : nil
        - size293 : nil
        - size310 : nil
        - size510 : nil
        - size820 : nil
        - size1024 : nil
    ▿ published_at : Optional<String>
      - some : "2018-02-06T10:42:40+02:00"
    - updated_at : nil

Я что-то пропустил? Пожалуйста, помогите, ребята:-)

1 ответ

Решение

В Article.swift попробуйте изменить следующие строки

category = try Category(from: decoder)
main_image_urls = try Main_image_urls(from: decoder)

в

category = values.decodeIfPresent(Category.self, forKey: .category)
main_image_urls = values.decodeIfPresent(Main_image_urls.self, forKey: .main_image_urls)

Твой класс Main_image_urls также должен соответствовать кодируемым.

Вы также можете попытаться опустить init(from decoder: Decoder) методы и пусть компилятор синтезирует его. Это также работает при наличии пользовательского перечисления CodingKeys.

Обновить:

Также измените следующую строку в Category.swift

parent_category = try Parent_category(from: decoder)

в

parent_category = values.decodeIfPresent(Parent_category.self, forKey: .parentCategory)
Другие вопросы по тегам