I am trying to create a Codable extension that is capable of initialising a Decodable (Swift 4) object with only a json string. So what Should work is:
struct MyObject: Decodable {
var title: String?
}
let myObject = MyObject(json: "{\"title\":\"The title\"}")
I think this means that I should create an init that calls the self.init with a Decoder. Here is the code that I came up with:
public init?(json: String) throws {
guard let decoder: Decoder = GetDecoder.decode(json: json)?.decoder else { return }
try self.init(from: decoder) // Who what should we do to get it so that we can call this?
}
That code is capable of getting the decoder, but I get a compiler error on calling the init. The error that I get is:
'self' used before self.init call
Does this mean that there is no way to add an init to the Decodable protocol?
For the complete source code see the codable extension on github
update:
After debugging the solution below from @appzYourLive I found out that I had a conflict with the init(json:
initialisers on Decodable and Array. I just published a new version of the extension to GitHub. I also added the solution as a new answer to this question.
A possible workaround
A possible solution is defining another protocol
protocol DecodableFromString: Decodable { }
with its own initializer
extension DecodableFromString {
init?(from json: String) throws {
guard let data = try json.data(using: .utf8) else { return nil }
guard let value = try? JSONDecoder().decode(Self.self, from: data) else { return nil }
self = value
}
}
Now you need to conform your type to DecodableFromString
struct Person:Codable, DecodableFromString {
let firstName: String
let lastName: String
}
And finally given a JSON
let json = """
{
"firstName": "Luke",
"lastName": "Skywalker"
}
"""
you can build your value
if let luke = try? Person(from: json) {
print(luke)
}
Person(firstName: "Luke", lastName: "Skywalker")
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