I'm currently working with Codable
types in my project and facing an issue.
struct Person: Codable
{
var id: Any
}
id
in the above code could be either a String
or an Int
. This is the reason id
is of type Any
.
I know that Any
is not Codable
.
What I need to know is how can I make it work.
If all the properties of a type already conform to Codable , then the type itself can conform to Codable with no extra work – Swift will synthesize the code required to archive and unarchive your type as needed.
Codable allows you to insert an additional clarifying stage into the process of decoding data into a Swift object. This stage is the “parsed object,” whose properties and keys match up directly to the data, but whose types have been decoded into Swift objects.
The simplest way to make a type codable is to declare its properties using types that are already Codable . These types include standard library types like String , Int , and Double ; and Foundation types like Date , Data , and URL .
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
}
}
Now you can define your struct like this
struct Person: Decodable {
let id: QuantumValue
}
That's it. Let's test it!
id
is String
let data = """
{
"id": "123"
}
""".data(using: String.Encoding.utf8)!
if let person = try? JSONDecoder().decode(Person.self, from: data) {
print(person)
}
id
is Int
let data = """
{
"id": 123
}
""".data(using: String.Encoding.utf8)!
if let person = try? JSONDecoder().decode(Person.self, from: data) {
print(person)
}
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
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.
Codable needs to know the type to cast to.
Firstly I would try to address the issue of not knowing the type, see if you can fix that and make it simpler.
Otherwise the only way I can think of solving your issue currently is to use generics like below.
struct Person<T> {
var id: T
var name: String
}
let person1 = Person<Int>(id: 1, name: "John")
let person2 = Person<String>(id: "two", name: "Steve")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With