7

I'm working with the docodable protocol and I'm having this error:

typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [MakeApp_v2.Params.(CodingKeys in _244BBB2F32A8C5CF3DB84B0C6A94B232).config, Swift._DictionaryCodingKey(stringValue: "table", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found a string/data instead.", underlyingError: nil))

Here's the JSON that I encouter an error

{
  "callBackID" : "add1867f-6005-189c-bbb4-ff53202b0697",
  "config" : {
    "description" : "Welcome Page",
    "show-bottom-bar" : "",
    "css-page-align" : "",
    "footer" : { "show" : "", "object" : "bottom-bar" },
    "pageStyle" : "full-page",
    "sourceType" : "list",
    "title" : "Welcome Page",
    "header" : { "show" : true, "hide" : false, "object" : "top-bar" },
    "columns" : {},
    "objects" : {},
    "showtabs" : true,
    "slides" : [{"title" : "first section","map" : ["open"]}],
    "table" : "",
    "show-top-bar" : true,
    "style_max-width" : "",
    "slideType" : "slide"
  },
  "method" : 106,
  "parName" : "A1519614709427",
  "formid" : "1"
}

My struct

struct Params: Decodable {
  let callBackID: String, method: Int, parName: String, pageID: String?, table: String?, fields: [String: Properties]?, imageid: String?, imagetable: String?, config: [String: Config]?, appTemplate: String?, appName: String?, values: Properties?, columns: [String: Properties]?, filter: [String: Properties]?

  private enum CodingKeys: String, CodingKey {
    case callBackID = "callBackID", method = "method", parName = "parName", pageID = "pageID", table = "table", fields = "fields", imageid = "imageid", imagetable = "imagetable", config = "config", appTemplate = "appTemplate", appName = "appName", values = "values", columns = "columns", filter = "filter"
  }
}

struct Properties: Decodable {
  let source: String?, type: String?, rec_id: String?, name: String?, value: String?
}

struct Config: Decodable {
  let table: String?

  private enum CodingKeys: String, CodingKey {
    case table = "table"
  }
}

Getting the JSON data

var param: Params?
do {
    let jsonData = try JSONSerialization.data(withJSONObject: message.body, options: .prettyPrinted)
    print(String(data: jsonData, encoding: .utf8)!)
    param = try JSONDecoder().decode(Params.self, from: jsonData)
    print(param!)
} catch {
    print(error)
}
methods(param: param!)
print(methods)
}

func methods(param: Params) -> String { return "some string" }

I have 3 sets of JSON data structure, the first two sets are working fine with this structure, but the one JSON data above make the program stop. Im not sure what to update on my code. I hope you can help me to resolve this problem, TIA!

riogarrell
  • 103
  • 1
  • 10
  • The problem is your `config: [String: Config]?` inside `Params` structure. From the JSON, it's clearly noticeable that your key is `config` and the value would be a `Config` type object _not the `Dictionary` type_. So changing the config property to `config: Config?` should resolve the problem. – nayem Mar 05 '18 at 07:25
  • lol, i didnt notice that. maybe im still nub to this. hehe thanks @nayem – riogarrell Mar 05 '18 at 08:01

2 Answers2

3

Well I'm just converting my comment into an answer for more clarity.

The problem is your config: [String: Config]? inside Params structure. From the JSON, it's clearly noticeable that your key is config and the value would be a Config type object not the Dictionary type. So change the config property to config: Config?.

Another note: when the properties in your struct are same as the JSON keys, you can omit the CodingKeys enum (as like you did with your Properties struct)

Extra note: I'm seeing a lot of optionals in your struct definitions. Please consider only the cases when you really need the optional types. Don't just use them unnecessarily.

struct Params: Decodable {
    let callBackID: String
    let method: Int
    let parName: String
    let pageID: String?
    let table: String?
    let fields: [String: Properties]?
    let imageid: String?
    let imagetable: String?
    let config: Config?
    let appTemplate: String?
    let appName: String?
    let values: Properties?
    let columns: [String: Properties]?
    let filter: [String: Properties]?
}

For further notes, what I suspect more is, you will also get in troubles with your [String: Properties]? types later. It's more like this config property I suspect.

nayem
  • 7,285
  • 1
  • 33
  • 51
  • more on my keys are realy an optional, because on my api i send different json structures, some keys are present, or present but nil value; and somtimes i dont send those keys. – riogarrell Mar 05 '18 at 08:13
  • Hi! @nayem, I have additional question. Base on my json above, how can i display the datas of "config"? I think my struct Config is not a help. – riogarrell Mar 07 '18 at 07:23
1
struct Params: Decodable {
  let callBackID: String, method: Int, parName: String, pageID: String?, table: String?, fields: [String: Properties]?, imageid: String?, imagetable: String?, config: Config?, appTemplate: String?, appName: String?, values: Properties?, columns: [String: Properties]?, filter: [String: Properties]?

  private enum CodingKeys: String, CodingKey {
    case callBackID = "callBackID", method = "method", parName = "parName", pageID = "pageID", table = "table", fields = "fields", imageid = "imageid", imagetable = "imagetable", config = "config", appTemplate = "appTemplate", appName = "appName", values = "values", columns = "columns", filter = "filter"
  }
}

struct Properties: Decodable {
  let source: String?, type: String?, rec_id: String?, name: String?, value: String?
}

struct Config: Decodable {
  let table: String?

  private enum CodingKeys: String, CodingKey {
    case table = "table"
  }
}

Sorry my bad! wrong type of object for my key config. instead config = [String: Config?] change to config = Config? credit to @nayem

riogarrell
  • 103
  • 1
  • 10