How to parse JSON with Decodable protocol when property types might change from Int to String?

前端 未结 4 570
清歌不尽
清歌不尽 2020-12-03 16:13

I have to decode a JSON with a big structure and a lot of nested arrays. I have reproduced the structure in my UserModel file, and it works, except with one property (postco

4条回答
  •  孤街浪徒
    2020-12-03 16:46

    If postcode can be both String and Int, you have (at least) two possible solutions for this issue. Firstly, you can simply store all postcodes as String, since all Ints can be converted to String. This seems like the best solution, since it seems highly unlikely that you'd need to perform any numeric operations on a postcode, especially if some postcodes can be String. The other solution would be creating two properties for postcode, one of type String? and one of type Int? and always only populating one of the two depending on the input data, as explained in Using codable with key that is sometimes an Int and other times a String.

    The solution storing all postcodes as String:

    struct PostModel: Equatable, Decodable {
        static func ==(lhs: PostModel, rhs: PostModel) -> Bool {
            return lhs.userId == rhs.userId && lhs.id == rhs.id && lhs.title == rhs.title && lhs.body == rhs.body
        }
    
        var userId: Int
        var id: Int
        var title: String
        var body: String
        var postcode: String
    
        enum CodingKeys: String, CodingKey {
            case userId, id, title, body, postcode
        }
    
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            self.userId = try container.decode(Int.self, forKey: .userId)
            self.id = try container.decode(Int.self, forKey: .id)
            self.title = try container.decode(String.self, forKey: .title)
            self.body = try container.decode(String.self, forKey: .body)
            if let postcode = try? container.decode(String.self, forKey: .postcode) {
                self.postcode = postcode
            } else {
                let numericPostcode = try container.decode(Int.self, forKey: .postcode)
                self.postcode = "\(numericPostcode)"
            }
        }
    }
    

提交回复
热议问题