Home > Software engineering >  Swift decodable snake case key which include numbers Issue
Swift decodable snake case key which include numbers Issue

Time:02-28

I have a problem decoding JSON which has keys in the snake case including numbers. I've already spent days trying to solve it and can't tell I see any solution to it. Even though I need it badly. Nor do I have an idea why it is failing. Any help here is appreciated. Thanks!

for example JSON:

{
  "result": [
    {
      "symbol": "A",
      "v_price_24h": "39652.50",

    }
  ],
  "time_now": "1645931312.379455"
}

Will throw error:

keyNotFound(CodingKeys(stringValue: "vPrice24h", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "result", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"vPrice24h\", intValue: nil) (\"vPrice24h\").", underlyingError: nil))

my model property is vPrice24h key v_price_24h is in JSON

This works for everything but fails when I have a number in a key

decoder.keyDecodingStrategy = .convertFromSnakeCase

same stuff with my custom one: I spent days trying to figure it out and can't solve this issue. Does anyone know how to deal with it?

Here is playground:

import Foundation

var json = """
{
  "result": [
    {
      "symbol": "A",
      "v_price_24h": "39652.50",

    }
  ],
  "time_now": "1645931312.379455"
}
"""

struct CustomKey: CodingKey {
    let stringValue: String
    let intValue: Int?

    init(stringValue: String) {
        self.stringValue = stringValue
        intValue = nil
    }

    init(intValue: Int) {
        self.intValue = intValue
        stringValue = String(intValue)
    }
}

struct TopModel: Decodable {
    let timeNow: String
    let result: [InsideModel]
}

struct InsideModel: Decodable {
    enum CodingKeys: String, CodingKey {
        case symbol = "symbol"
        case vPrice24h = "v_price_24h"
    }
    let symbol: String
    let vPrice24h: String
}


let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase


let decoder2 = JSONDecoder()
decoder2.keyDecodingStrategy = .custom { keys in
    let last = keys.last!.stringValue
    let snakePattern :String = "(\\w{0,1})_"
    var key = last.capitalized.replacingOccurrences(of: snakePattern, with: "$1", options: .regularExpression, range: nil)

    if key.count > 1 {
        key = key.prefix(1).lowercased()   key.dropFirst()
    }
    print(key, last)
    return CustomKey(stringValue: key)
}

let decoder3 = JSONDecoder()
decoder3.keyDecodingStrategy = .useDefaultKeys

do {
    _ = try decoder.decode(TopModel.self, from: json.data(using: .utf8)!)
} catch let thrownError {
    print("           
  • Related