Decode json with dynamic coding key using Codable?












0















Example of Json I need to decode. In "text" key we have [String: String] dict. And quantity of elements is in "count". How should I decode it properly?



{
"name": "LoremIpsum",
"index": "1",
"text": {
"text_1": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ",
"text_2": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ",
"text_3": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. ",
"text_4": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
},
"count": "4"
}


My Codable model:



class Text: Codable {

private enum CodingKeys: String, CodingKey {
case name, index, count, text
}

public var name: String?
public var index: Int?
public var count: Int?
public var texts: [String]?

init() {
name = ""
index = 0
count = 0
texts =
}

init(name: String,
index: Int,
count: Int,
texts: [String]) {
self.name = name
self.index = index
self.count = count
self.texts = texts
}

func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
var text = container.nestedContainer(keyedBy: CodingKeys.self, forKey: . text)

} <---- also why do I need this method?

required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

self.name = try container.decode(String.self, forKey: .name)
self.index = Int(try container.decode(String.self, forKey: .index)) ?? 0
self.count = Int(try container.decode(String.self, forKey: .count)) ?? 0
let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)

for i in (1...self.count!) {
self.texts!.append(try text.decode(String.self, forKey: Text.CodingKeys.init(rawValue: "text_(i)") ?? .text))
}
}

}


And I decode it with:



if let path = Bundle.main.path(forResource: "en_translation_001", ofType: "json") {
do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped)
let jsonObj = try JSONDecoder().decode(Text.self, from: data)
print("jsonData:(jsonObj)")
} catch let error {
print("parse error: (error.localizedDescription)")
}
} else {
print("Invalid filename/path.")
}


But I got parse error




parse error: The data couldn’t be read because it is missing.




What is wrong with my code? Is it a good way to decode such dynamic coding keys?










share|improve this question



























    0















    Example of Json I need to decode. In "text" key we have [String: String] dict. And quantity of elements is in "count". How should I decode it properly?



    {
    "name": "LoremIpsum",
    "index": "1",
    "text": {
    "text_1": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ",
    "text_2": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ",
    "text_3": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. ",
    "text_4": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
    },
    "count": "4"
    }


    My Codable model:



    class Text: Codable {

    private enum CodingKeys: String, CodingKey {
    case name, index, count, text
    }

    public var name: String?
    public var index: Int?
    public var count: Int?
    public var texts: [String]?

    init() {
    name = ""
    index = 0
    count = 0
    texts =
    }

    init(name: String,
    index: Int,
    count: Int,
    texts: [String]) {
    self.name = name
    self.index = index
    self.count = count
    self.texts = texts
    }

    func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    var text = container.nestedContainer(keyedBy: CodingKeys.self, forKey: . text)

    } <---- also why do I need this method?

    required public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)

    self.name = try container.decode(String.self, forKey: .name)
    self.index = Int(try container.decode(String.self, forKey: .index)) ?? 0
    self.count = Int(try container.decode(String.self, forKey: .count)) ?? 0
    let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)

    for i in (1...self.count!) {
    self.texts!.append(try text.decode(String.self, forKey: Text.CodingKeys.init(rawValue: "text_(i)") ?? .text))
    }
    }

    }


    And I decode it with:



    if let path = Bundle.main.path(forResource: "en_translation_001", ofType: "json") {
    do {
    let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped)
    let jsonObj = try JSONDecoder().decode(Text.self, from: data)
    print("jsonData:(jsonObj)")
    } catch let error {
    print("parse error: (error.localizedDescription)")
    }
    } else {
    print("Invalid filename/path.")
    }


    But I got parse error




    parse error: The data couldn’t be read because it is missing.




    What is wrong with my code? Is it a good way to decode such dynamic coding keys?










    share|improve this question

























      0












      0








      0








      Example of Json I need to decode. In "text" key we have [String: String] dict. And quantity of elements is in "count". How should I decode it properly?



      {
      "name": "LoremIpsum",
      "index": "1",
      "text": {
      "text_1": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ",
      "text_2": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ",
      "text_3": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. ",
      "text_4": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
      },
      "count": "4"
      }


      My Codable model:



      class Text: Codable {

      private enum CodingKeys: String, CodingKey {
      case name, index, count, text
      }

      public var name: String?
      public var index: Int?
      public var count: Int?
      public var texts: [String]?

      init() {
      name = ""
      index = 0
      count = 0
      texts =
      }

      init(name: String,
      index: Int,
      count: Int,
      texts: [String]) {
      self.name = name
      self.index = index
      self.count = count
      self.texts = texts
      }

      func encode(to encoder: Encoder) throws {
      var container = encoder.container(keyedBy: CodingKeys.self)
      var text = container.nestedContainer(keyedBy: CodingKeys.self, forKey: . text)

      } <---- also why do I need this method?

      required public init(from decoder: Decoder) throws {
      let container = try decoder.container(keyedBy: CodingKeys.self)

      self.name = try container.decode(String.self, forKey: .name)
      self.index = Int(try container.decode(String.self, forKey: .index)) ?? 0
      self.count = Int(try container.decode(String.self, forKey: .count)) ?? 0
      let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)

      for i in (1...self.count!) {
      self.texts!.append(try text.decode(String.self, forKey: Text.CodingKeys.init(rawValue: "text_(i)") ?? .text))
      }
      }

      }


      And I decode it with:



      if let path = Bundle.main.path(forResource: "en_translation_001", ofType: "json") {
      do {
      let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped)
      let jsonObj = try JSONDecoder().decode(Text.self, from: data)
      print("jsonData:(jsonObj)")
      } catch let error {
      print("parse error: (error.localizedDescription)")
      }
      } else {
      print("Invalid filename/path.")
      }


      But I got parse error




      parse error: The data couldn’t be read because it is missing.




      What is wrong with my code? Is it a good way to decode such dynamic coding keys?










      share|improve this question














      Example of Json I need to decode. In "text" key we have [String: String] dict. And quantity of elements is in "count". How should I decode it properly?



      {
      "name": "LoremIpsum",
      "index": "1",
      "text": {
      "text_1": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ",
      "text_2": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ",
      "text_3": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. ",
      "text_4": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
      },
      "count": "4"
      }


      My Codable model:



      class Text: Codable {

      private enum CodingKeys: String, CodingKey {
      case name, index, count, text
      }

      public var name: String?
      public var index: Int?
      public var count: Int?
      public var texts: [String]?

      init() {
      name = ""
      index = 0
      count = 0
      texts =
      }

      init(name: String,
      index: Int,
      count: Int,
      texts: [String]) {
      self.name = name
      self.index = index
      self.count = count
      self.texts = texts
      }

      func encode(to encoder: Encoder) throws {
      var container = encoder.container(keyedBy: CodingKeys.self)
      var text = container.nestedContainer(keyedBy: CodingKeys.self, forKey: . text)

      } <---- also why do I need this method?

      required public init(from decoder: Decoder) throws {
      let container = try decoder.container(keyedBy: CodingKeys.self)

      self.name = try container.decode(String.self, forKey: .name)
      self.index = Int(try container.decode(String.self, forKey: .index)) ?? 0
      self.count = Int(try container.decode(String.self, forKey: .count)) ?? 0
      let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)

      for i in (1...self.count!) {
      self.texts!.append(try text.decode(String.self, forKey: Text.CodingKeys.init(rawValue: "text_(i)") ?? .text))
      }
      }

      }


      And I decode it with:



      if let path = Bundle.main.path(forResource: "en_translation_001", ofType: "json") {
      do {
      let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped)
      let jsonObj = try JSONDecoder().decode(Text.self, from: data)
      print("jsonData:(jsonObj)")
      } catch let error {
      print("parse error: (error.localizedDescription)")
      }
      } else {
      print("Invalid filename/path.")
      }


      But I got parse error




      parse error: The data couldn’t be read because it is missing.




      What is wrong with my code? Is it a good way to decode such dynamic coding keys?







      json swift decode codable






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 13 '18 at 13:43









      Said-Abdulla AtkaevSaid-Abdulla Atkaev

      499410




      499410
























          3 Answers
          3






          active

          oldest

          votes


















          1














          You need



          struct Root: Codable {
          let name, index,count: String
          let text: [String:String]
          }


          --



          let res = try? JSONDecoder().decode(Root.self,from:jsonData)





          share|improve this answer


























          • The thing is that there can be text5, text6 and textN Depending on "count"

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:55













          • @Said-AbdullaAtkaev use only that struct and the decode should work

            – Sh_Khan
            Nov 13 '18 at 13:57





















          2














          Fix JSON



          I suppose you want your index and count to be numbers. So replace this "index": "1" and this "count": "4"
          With this "index": 1 and this "count": 4



          Class structure



          With Codable protocol any of these CodingKeys and encode functions or required inits aren't neccessary. Also change texts property data format to [String: String]



          So, replace your class like this:



          class Text: Codable {

          public var name: String
          public var index: Int
          public var count: Int
          public var texts: [String: String]

          init(name: String, index: Int, count: Int, texts: [String: String]) {
          self.name = name
          self.index = index
          self.count = count
          self.texts = texts
          }

          }


          Decoding



          For decoding your json use what you wrote above, this is correct



          let object = try JSONDecoder().decode(Text.self, from: data)





          share|improve this answer


























          • So how should I decode this json?

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:50











          • @Said-AbdullaAtkaev Read edited answer. You were decoding your json right, but your class was wrong.

            – Robert Dresler
            Nov 13 '18 at 13:53











          • index and count are not ints plus texts is a dictionary not array

            – Sh_Khan
            Nov 13 '18 at 13:57











          • I need to remove all inits and also "init(from decoder: Decoder)" ?

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:57











          • @Said-AbdullaAtkaev if you want to, you can keep your init(name: String....

            – Robert Dresler
            Nov 13 '18 at 13:59



















          1














          The most important thing you need is this:



          let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)
          texts = try text.allKeys.map { try text.decode(String.self, forKey: $0) }


          This will convert the dictionary into an array of values. While in principle JSON values are not ordered, allKeys is ordered (because it's a serialized protocol).



          You wouldn't need the encode method if you conformed only to Decodable rather than Codable. Also, most of your optionals are not really optionals.



          Putting those things together, you would have this:



          class Text: Decodable {

          private enum CodingKeys: String, CodingKey {
          case name, index, count, text
          }

          public var name: String
          public var index: Int
          public var count: Int
          public var texts: [String]

          init(name: String = "",
          index: Int = 0,
          count: Int = 0,
          texts: [String] = ) {
          self.name = name
          self.index = index
          self.count = count
          self.texts = texts
          }

          required public init(from decoder: Decoder) throws {
          let container = try decoder.container(keyedBy: CodingKeys.self)

          self.name = try container.decode(String.self, forKey: .name)
          self.index = Int(try container.decode(String.self, forKey: .index)) ?? 0
          self.count = Int(try container.decode(String.self, forKey: .count)) ?? 0
          let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)
          texts = try text.allKeys.map { try text.decode(String.self, forKey: $0) }
          }

          }

          let jsonObj = try JSONDecoder().decode(Text.self, from: data)





          share|improve this answer
























          • I think this should be a server response fix not a local code

            – Sh_Khan
            Nov 13 '18 at 14:11











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53282380%2fdecode-json-with-dynamic-coding-key-using-codable%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          3 Answers
          3






          active

          oldest

          votes








          3 Answers
          3






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          You need



          struct Root: Codable {
          let name, index,count: String
          let text: [String:String]
          }


          --



          let res = try? JSONDecoder().decode(Root.self,from:jsonData)





          share|improve this answer


























          • The thing is that there can be text5, text6 and textN Depending on "count"

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:55













          • @Said-AbdullaAtkaev use only that struct and the decode should work

            – Sh_Khan
            Nov 13 '18 at 13:57


















          1














          You need



          struct Root: Codable {
          let name, index,count: String
          let text: [String:String]
          }


          --



          let res = try? JSONDecoder().decode(Root.self,from:jsonData)





          share|improve this answer


























          • The thing is that there can be text5, text6 and textN Depending on "count"

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:55













          • @Said-AbdullaAtkaev use only that struct and the decode should work

            – Sh_Khan
            Nov 13 '18 at 13:57
















          1












          1








          1







          You need



          struct Root: Codable {
          let name, index,count: String
          let text: [String:String]
          }


          --



          let res = try? JSONDecoder().decode(Root.self,from:jsonData)





          share|improve this answer















          You need



          struct Root: Codable {
          let name, index,count: String
          let text: [String:String]
          }


          --



          let res = try? JSONDecoder().decode(Root.self,from:jsonData)






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 13 '18 at 13:56

























          answered Nov 13 '18 at 13:55









          Sh_KhanSh_Khan

          40.5k51125




          40.5k51125













          • The thing is that there can be text5, text6 and textN Depending on "count"

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:55













          • @Said-AbdullaAtkaev use only that struct and the decode should work

            – Sh_Khan
            Nov 13 '18 at 13:57





















          • The thing is that there can be text5, text6 and textN Depending on "count"

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:55













          • @Said-AbdullaAtkaev use only that struct and the decode should work

            – Sh_Khan
            Nov 13 '18 at 13:57



















          The thing is that there can be text5, text6 and textN Depending on "count"

          – Said-Abdulla Atkaev
          Nov 13 '18 at 13:55







          The thing is that there can be text5, text6 and textN Depending on "count"

          – Said-Abdulla Atkaev
          Nov 13 '18 at 13:55















          @Said-AbdullaAtkaev use only that struct and the decode should work

          – Sh_Khan
          Nov 13 '18 at 13:57







          @Said-AbdullaAtkaev use only that struct and the decode should work

          – Sh_Khan
          Nov 13 '18 at 13:57















          2














          Fix JSON



          I suppose you want your index and count to be numbers. So replace this "index": "1" and this "count": "4"
          With this "index": 1 and this "count": 4



          Class structure



          With Codable protocol any of these CodingKeys and encode functions or required inits aren't neccessary. Also change texts property data format to [String: String]



          So, replace your class like this:



          class Text: Codable {

          public var name: String
          public var index: Int
          public var count: Int
          public var texts: [String: String]

          init(name: String, index: Int, count: Int, texts: [String: String]) {
          self.name = name
          self.index = index
          self.count = count
          self.texts = texts
          }

          }


          Decoding



          For decoding your json use what you wrote above, this is correct



          let object = try JSONDecoder().decode(Text.self, from: data)





          share|improve this answer


























          • So how should I decode this json?

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:50











          • @Said-AbdullaAtkaev Read edited answer. You were decoding your json right, but your class was wrong.

            – Robert Dresler
            Nov 13 '18 at 13:53











          • index and count are not ints plus texts is a dictionary not array

            – Sh_Khan
            Nov 13 '18 at 13:57











          • I need to remove all inits and also "init(from decoder: Decoder)" ?

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:57











          • @Said-AbdullaAtkaev if you want to, you can keep your init(name: String....

            – Robert Dresler
            Nov 13 '18 at 13:59
















          2














          Fix JSON



          I suppose you want your index and count to be numbers. So replace this "index": "1" and this "count": "4"
          With this "index": 1 and this "count": 4



          Class structure



          With Codable protocol any of these CodingKeys and encode functions or required inits aren't neccessary. Also change texts property data format to [String: String]



          So, replace your class like this:



          class Text: Codable {

          public var name: String
          public var index: Int
          public var count: Int
          public var texts: [String: String]

          init(name: String, index: Int, count: Int, texts: [String: String]) {
          self.name = name
          self.index = index
          self.count = count
          self.texts = texts
          }

          }


          Decoding



          For decoding your json use what you wrote above, this is correct



          let object = try JSONDecoder().decode(Text.self, from: data)





          share|improve this answer


























          • So how should I decode this json?

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:50











          • @Said-AbdullaAtkaev Read edited answer. You were decoding your json right, but your class was wrong.

            – Robert Dresler
            Nov 13 '18 at 13:53











          • index and count are not ints plus texts is a dictionary not array

            – Sh_Khan
            Nov 13 '18 at 13:57











          • I need to remove all inits and also "init(from decoder: Decoder)" ?

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:57











          • @Said-AbdullaAtkaev if you want to, you can keep your init(name: String....

            – Robert Dresler
            Nov 13 '18 at 13:59














          2












          2








          2







          Fix JSON



          I suppose you want your index and count to be numbers. So replace this "index": "1" and this "count": "4"
          With this "index": 1 and this "count": 4



          Class structure



          With Codable protocol any of these CodingKeys and encode functions or required inits aren't neccessary. Also change texts property data format to [String: String]



          So, replace your class like this:



          class Text: Codable {

          public var name: String
          public var index: Int
          public var count: Int
          public var texts: [String: String]

          init(name: String, index: Int, count: Int, texts: [String: String]) {
          self.name = name
          self.index = index
          self.count = count
          self.texts = texts
          }

          }


          Decoding



          For decoding your json use what you wrote above, this is correct



          let object = try JSONDecoder().decode(Text.self, from: data)





          share|improve this answer















          Fix JSON



          I suppose you want your index and count to be numbers. So replace this "index": "1" and this "count": "4"
          With this "index": 1 and this "count": 4



          Class structure



          With Codable protocol any of these CodingKeys and encode functions or required inits aren't neccessary. Also change texts property data format to [String: String]



          So, replace your class like this:



          class Text: Codable {

          public var name: String
          public var index: Int
          public var count: Int
          public var texts: [String: String]

          init(name: String, index: Int, count: Int, texts: [String: String]) {
          self.name = name
          self.index = index
          self.count = count
          self.texts = texts
          }

          }


          Decoding



          For decoding your json use what you wrote above, this is correct



          let object = try JSONDecoder().decode(Text.self, from: data)






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 13 '18 at 14:05

























          answered Nov 13 '18 at 13:46









          Robert DreslerRobert Dresler

          4,9491526




          4,9491526













          • So how should I decode this json?

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:50











          • @Said-AbdullaAtkaev Read edited answer. You were decoding your json right, but your class was wrong.

            – Robert Dresler
            Nov 13 '18 at 13:53











          • index and count are not ints plus texts is a dictionary not array

            – Sh_Khan
            Nov 13 '18 at 13:57











          • I need to remove all inits and also "init(from decoder: Decoder)" ?

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:57











          • @Said-AbdullaAtkaev if you want to, you can keep your init(name: String....

            – Robert Dresler
            Nov 13 '18 at 13:59



















          • So how should I decode this json?

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:50











          • @Said-AbdullaAtkaev Read edited answer. You were decoding your json right, but your class was wrong.

            – Robert Dresler
            Nov 13 '18 at 13:53











          • index and count are not ints plus texts is a dictionary not array

            – Sh_Khan
            Nov 13 '18 at 13:57











          • I need to remove all inits and also "init(from decoder: Decoder)" ?

            – Said-Abdulla Atkaev
            Nov 13 '18 at 13:57











          • @Said-AbdullaAtkaev if you want to, you can keep your init(name: String....

            – Robert Dresler
            Nov 13 '18 at 13:59

















          So how should I decode this json?

          – Said-Abdulla Atkaev
          Nov 13 '18 at 13:50





          So how should I decode this json?

          – Said-Abdulla Atkaev
          Nov 13 '18 at 13:50













          @Said-AbdullaAtkaev Read edited answer. You were decoding your json right, but your class was wrong.

          – Robert Dresler
          Nov 13 '18 at 13:53





          @Said-AbdullaAtkaev Read edited answer. You were decoding your json right, but your class was wrong.

          – Robert Dresler
          Nov 13 '18 at 13:53













          index and count are not ints plus texts is a dictionary not array

          – Sh_Khan
          Nov 13 '18 at 13:57





          index and count are not ints plus texts is a dictionary not array

          – Sh_Khan
          Nov 13 '18 at 13:57













          I need to remove all inits and also "init(from decoder: Decoder)" ?

          – Said-Abdulla Atkaev
          Nov 13 '18 at 13:57





          I need to remove all inits and also "init(from decoder: Decoder)" ?

          – Said-Abdulla Atkaev
          Nov 13 '18 at 13:57













          @Said-AbdullaAtkaev if you want to, you can keep your init(name: String....

          – Robert Dresler
          Nov 13 '18 at 13:59





          @Said-AbdullaAtkaev if you want to, you can keep your init(name: String....

          – Robert Dresler
          Nov 13 '18 at 13:59











          1














          The most important thing you need is this:



          let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)
          texts = try text.allKeys.map { try text.decode(String.self, forKey: $0) }


          This will convert the dictionary into an array of values. While in principle JSON values are not ordered, allKeys is ordered (because it's a serialized protocol).



          You wouldn't need the encode method if you conformed only to Decodable rather than Codable. Also, most of your optionals are not really optionals.



          Putting those things together, you would have this:



          class Text: Decodable {

          private enum CodingKeys: String, CodingKey {
          case name, index, count, text
          }

          public var name: String
          public var index: Int
          public var count: Int
          public var texts: [String]

          init(name: String = "",
          index: Int = 0,
          count: Int = 0,
          texts: [String] = ) {
          self.name = name
          self.index = index
          self.count = count
          self.texts = texts
          }

          required public init(from decoder: Decoder) throws {
          let container = try decoder.container(keyedBy: CodingKeys.self)

          self.name = try container.decode(String.self, forKey: .name)
          self.index = Int(try container.decode(String.self, forKey: .index)) ?? 0
          self.count = Int(try container.decode(String.self, forKey: .count)) ?? 0
          let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)
          texts = try text.allKeys.map { try text.decode(String.self, forKey: $0) }
          }

          }

          let jsonObj = try JSONDecoder().decode(Text.self, from: data)





          share|improve this answer
























          • I think this should be a server response fix not a local code

            – Sh_Khan
            Nov 13 '18 at 14:11
















          1














          The most important thing you need is this:



          let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)
          texts = try text.allKeys.map { try text.decode(String.self, forKey: $0) }


          This will convert the dictionary into an array of values. While in principle JSON values are not ordered, allKeys is ordered (because it's a serialized protocol).



          You wouldn't need the encode method if you conformed only to Decodable rather than Codable. Also, most of your optionals are not really optionals.



          Putting those things together, you would have this:



          class Text: Decodable {

          private enum CodingKeys: String, CodingKey {
          case name, index, count, text
          }

          public var name: String
          public var index: Int
          public var count: Int
          public var texts: [String]

          init(name: String = "",
          index: Int = 0,
          count: Int = 0,
          texts: [String] = ) {
          self.name = name
          self.index = index
          self.count = count
          self.texts = texts
          }

          required public init(from decoder: Decoder) throws {
          let container = try decoder.container(keyedBy: CodingKeys.self)

          self.name = try container.decode(String.self, forKey: .name)
          self.index = Int(try container.decode(String.self, forKey: .index)) ?? 0
          self.count = Int(try container.decode(String.self, forKey: .count)) ?? 0
          let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)
          texts = try text.allKeys.map { try text.decode(String.self, forKey: $0) }
          }

          }

          let jsonObj = try JSONDecoder().decode(Text.self, from: data)





          share|improve this answer
























          • I think this should be a server response fix not a local code

            – Sh_Khan
            Nov 13 '18 at 14:11














          1












          1








          1







          The most important thing you need is this:



          let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)
          texts = try text.allKeys.map { try text.decode(String.self, forKey: $0) }


          This will convert the dictionary into an array of values. While in principle JSON values are not ordered, allKeys is ordered (because it's a serialized protocol).



          You wouldn't need the encode method if you conformed only to Decodable rather than Codable. Also, most of your optionals are not really optionals.



          Putting those things together, you would have this:



          class Text: Decodable {

          private enum CodingKeys: String, CodingKey {
          case name, index, count, text
          }

          public var name: String
          public var index: Int
          public var count: Int
          public var texts: [String]

          init(name: String = "",
          index: Int = 0,
          count: Int = 0,
          texts: [String] = ) {
          self.name = name
          self.index = index
          self.count = count
          self.texts = texts
          }

          required public init(from decoder: Decoder) throws {
          let container = try decoder.container(keyedBy: CodingKeys.self)

          self.name = try container.decode(String.self, forKey: .name)
          self.index = Int(try container.decode(String.self, forKey: .index)) ?? 0
          self.count = Int(try container.decode(String.self, forKey: .count)) ?? 0
          let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)
          texts = try text.allKeys.map { try text.decode(String.self, forKey: $0) }
          }

          }

          let jsonObj = try JSONDecoder().decode(Text.self, from: data)





          share|improve this answer













          The most important thing you need is this:



          let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)
          texts = try text.allKeys.map { try text.decode(String.self, forKey: $0) }


          This will convert the dictionary into an array of values. While in principle JSON values are not ordered, allKeys is ordered (because it's a serialized protocol).



          You wouldn't need the encode method if you conformed only to Decodable rather than Codable. Also, most of your optionals are not really optionals.



          Putting those things together, you would have this:



          class Text: Decodable {

          private enum CodingKeys: String, CodingKey {
          case name, index, count, text
          }

          public var name: String
          public var index: Int
          public var count: Int
          public var texts: [String]

          init(name: String = "",
          index: Int = 0,
          count: Int = 0,
          texts: [String] = ) {
          self.name = name
          self.index = index
          self.count = count
          self.texts = texts
          }

          required public init(from decoder: Decoder) throws {
          let container = try decoder.container(keyedBy: CodingKeys.self)

          self.name = try container.decode(String.self, forKey: .name)
          self.index = Int(try container.decode(String.self, forKey: .index)) ?? 0
          self.count = Int(try container.decode(String.self, forKey: .count)) ?? 0
          let text = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .text)
          texts = try text.allKeys.map { try text.decode(String.self, forKey: $0) }
          }

          }

          let jsonObj = try JSONDecoder().decode(Text.self, from: data)






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 13 '18 at 14:08









          Rob NapierRob Napier

          200k28294420




          200k28294420













          • I think this should be a server response fix not a local code

            – Sh_Khan
            Nov 13 '18 at 14:11



















          • I think this should be a server response fix not a local code

            – Sh_Khan
            Nov 13 '18 at 14:11

















          I think this should be a server response fix not a local code

          – Sh_Khan
          Nov 13 '18 at 14:11





          I think this should be a server response fix not a local code

          – Sh_Khan
          Nov 13 '18 at 14:11


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53282380%2fdecode-json-with-dynamic-coding-key-using-codable%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Xamarin.iOS Cant Deploy on Iphone

          Glorious Revolution

          Dulmage-Mendelsohn matrix decomposition in Python