How to use Any in Codable Type

后端 未结 11 763
猫巷女王i
猫巷女王i 2020-11-29 04:20

I\'m currently working with Codable types in my project and facing an issue.

struct Person: Codable
{
    var id: Any
}

11条回答
  •  暗喜
    暗喜 (楼主)
    2020-11-29 05:17

    Quantum Value

    First of all you can define a type that can be decoded both from a String and Int value. Here it is.

    enum QuantumValue: Decodable {
        
        case int(Int), string(String)
        
        init(from decoder: Decoder) throws {
            if let int = try? decoder.singleValueContainer().decode(Int.self) {
                self = .int(int)
                return
            }
            
            if let string = try? decoder.singleValueContainer().decode(String.self) {
                self = .string(string)
                return
            }
            
            throw QuantumError.missingValue
        }
        
        enum QuantumError:Error {
            case missingValue
        }
    }
    

    Person

    Now you can define your struct like this

    struct Person: Decodable {
        let id: QuantumValue
    }
    

    That's it. Let's test it!

    JSON 1: id is String

    let data = """
    {
    "id": "123"
    }
    """.data(using: String.Encoding.utf8)!
    
    if let person = try? JSONDecoder().decode(Person.self, from: data) {
        print(person)
    }
    

    JSON 2: id is Int

    let data = """
    {
    "id": 123
    }
    """.data(using: String.Encoding.utf8)!
    
    if let person = try? JSONDecoder().decode(Person.self, from: data) {
        print(person)
    }
    

    UPDATE 1 Comparing values

    This new paragraph should answer the questions from the comments.

    If you want to compare a quantum value to an Int you must keep in mind that a quantum value could contain an Int or a String.

    So the question is: what does it mean comparing a String and an Int?

    If you are just looking for a way of converting a quantum value into an Int then you can simply add this extension

    extension QuantumValue {
        
        var intValue: Int? {
            switch self {
            case .int(let value): return value
            case .string(let value): return Int(value)
            }
        }
    }
    

    Now you can write

    let quantumValue: QuantumValue: ...
    quantumValue.intValue == 123
    

    UPDATE 2

    This part to answer the comment left by @Abrcd18.

    You can add this computed property to the Person struct.

    var idAsString: String {
        switch id {
        case .string(let string): return string
        case .int(let int): return String(int)
        }
    }
    

    And now to populate the label just write

    label.text = person.idAsString
    

    Hope it helps.

提交回复
热议问题