1
votes

I have some JSON that I'm trying to decode with a Swift struct that conforms to the Codable protocol. The main struct doesn't seem to want to recognize the codingKey alias for thread_type, but happily consumes the explicitly named thread_id attribute. The struct in question is below:

struct Message: Codable {
var id: String?
var type: String?
var thread_id: String?
var threadType: String?
var sender: User?
var body: String?
var media: String?
var sentAt: Double?
var unread: Bool?
var status: String?
var url: String?

enum codingKeys: String, CodingKey {
    case id
    case type
    case thread_id
    case threadType = "thread_type"
    case sender
    case body
    case media
    case sentAt = "sent_at"
    case unread
    case status
    case url
}
}

The JSON that I'm trying to parse:

let json =
"""
{
"id": "Jvbl6LY",
"type": "sms",
"thread_id": "60LrVL7",
"thread_type": "578a",
"delay_until": null,
"sender": {
"id": "EVkdNBx",
"type": "user",
"first_name": "Jerry",
"last_name": "Ward",
"mobile_number": "123-456-7890",
"profile_image_url": "",
"is_online": false,
"email": "[email protected]"
},
"body": "Here is a picture of our Coquille Suite.  Let me know if you would like a reservation?",
"media": "",
"sent_at": 1509133604000.167,
"unread": false,
"status": "",
"url": "https://connect-staging.jypsee.com/api/sms/threads/60LrVL7/history/Jvbl6LY/"
}
"""

And finally the decoder call itself:

let decoder = JSONDecoder()
let data = json.data(using: .utf8)!
do {
    let message = try decoder.decode(Message.self, from: data)
    print(message.thread_id)
    print(message.threadType)
    print(message.sender?.firstName)
    print(message.sender?.lastName)
} catch {
    print(error)
}

The message.thread_id prints Optional("60LrVL7")\n" which is expected. The message.threadType prints nil\n, which is not expected. Even more bizarre is the fact that message.sender?.firstName and message.sender?.lastName both print "Optional("Jerry")\n" and "Optional("Ward")\n" respectively. Which means the nested User Codable Struct CodingKey IS working. I'm really at a loss as to why there's such an inconsistency in decoding.

Xcode Playground Gist is available here

1
CodingKeys, not codingKeys. - Hamish
Doh! Amazing what an extra set of eyes can do. Thank you! - James Jordan Taylor
Is every field really optional? You can be sent {} and you would expect to decode that as all nils (and you'd consider those nils different than empty strings or false)? The fact that profile_image_url is being sent as "" makes that very suspicious. Using this many optionals is typically a sign of a data problem. - Rob Napier
CodingKeys should be a private enum. - meaning-matters
Should be, but they don't have to be for them to work. - James Jordan Taylor

1 Answers

3
votes

Apple doc clearly states in the first sentence on the paragraph below. A special enumeration named 'CodingKeys' is necessary. (I had the similar problem and took me quite some time to find out).

enter image description here https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types