rshev
rshev

Reputation: 4176

Swift: calling failable initializer from throwing initializer?

I have a need to extend struct having failable initializer with a throwing initializer calling that failable initializer. And I see no elegant or clear way to do that in Swift 3.1.

Something like this:

extension Product: JSONDecodable {

    public enum Error: Swift.Error {
        case unableToParseJSON
    }

    init(decodeFromJSON json: JSON) throws {
        guard let jsonObject = json as? JSONObject else {
            throw Error.unableToParseJSON
        }

        // Meta-code
        self.init(dictionary: jsonObject) ?? throw Error.unableToParseJSON
    }
}

Is there an elegant and clean way to do that?

Upvotes: 6

Views: 1813

Answers (2)

rshev
rshev

Reputation: 4176

Found a semi-clean way to do that while writing the question:

extension Product: JSONDecodable {

    public enum Error: Swift.Error {
        case unableToParseJSON
    }

    init(decodeFromJSON json: JSON) throws {
        guard let jsonObject = json as? JSONObject,
            let initialized = Self(dictionary: jsonObject)
        else {
            throw Error.unableToParseJSON
        }
        
        self = initialized
    }
}

Upvotes: 16

David Peterson
David Peterson

Reputation: 19

The above is the best method I've seen, nice work. Just a small tweak that uses Self instead of type(of: self) for neatness:

extension Product: JSONDecodable {

    public enum Error: Swift.Error {
        case unableToParseJSON
    }

    init(decodeFromJSON json: JSON) throws {
        guard let jsonObject = json as? JSONObject,
            let initialized = Self.init(dictionary: jsonObject)
        else {
            throw Error.unableToParseJSON
        }

        self = initialized
    }
}

Upvotes: 0

Related Questions