0

I define a model like this:

struct DMTest: Codable {
    var uid: Int
    var name: String?
}

and do the model decode like this:

    let jsonStr = "{\"uid\":123,\"name\":\"haha\"}"
    let jsonData = jsonStr.data(using: .utf8)!

    do {
        let decoder = JSONDecoder()
        let result = try decoder.decode(DMTest.self, from:jsonData)
        XCGLogger.debug("result = \(result)")
    }catch {
        XCGLogger.debug("error")
    }

When jsonStr is like below, it works well:

{"uid":123,"name":"haha"}

when jsonStr is like below, it will throw a exception:

{"uid":"123","name":"haha"}

It means that if the type of the "uid" not adapter, it can't be decode. But some times the framework of server is weak type, it may give me dirty data like this, How can I adjust the type?

For example: I define Int in the model, if the server give some data of String type and I can covert it to Int, just decode to Int otherwise throw ecxeption.

qiushuitian
  • 1,261
  • 4
  • 19
  • 31
  • Possible duplicate of [Swift 4 Codable - Bool or String values](https://stackoverflow.com/questions/48621515/swift-4-codable-bool-or-string-values) – Larme Jul 17 '18 at 08:07
  • @Larme not very near. I want to decode all model of my app, Not a special model. If I do like that, it means I shold write lots of template code for every model. May be it is a chooes way. – qiushuitian Jul 17 '18 at 08:22
  • if your model encounters a situation like that , then you have no choice , there is no other way to decode a property with a possibility of 2 different types – Shehata Gamal Jul 17 '18 at 08:37
  • Actually @qiushuitian this is a duplicate. – Mackarous Jul 17 '18 at 09:16

1 Answers1

0

You can define a custom parsing solution:

struct DMTest: Codable {
    enum CodingKeys: String, CodingKey {
        case uid, name
    }
    var uid: Int
    var name: String?

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        if let stringUID = try? container.decode(String.self, forKey: .uid), let intUID = Int(stringUID) {
            uid = intUID
        } else if let intUID = try? container.decode(Int.self, forKey: .uid) {
            uid = intUID
        } else {
            uid = 0 // or throw error
        }
        name = try container.decodeIfPresent(String.self, forKey: .name)
    }
}
Mackarous
  • 1,467
  • 1
  • 11
  • 8