расширение классов Foundation для соответствия протоколу Swift

Я пытаюсь определить протокол, для которого я хотел бы добавить соответствие нескольким классам Foundation, а также некоторым собственным собственным типам. Сначала я попытался сделать это с помощью удобного инициализатора в протоколе, но это require-an-init">не представляется возможным. Я читал в связанную ветку на форумах разработчиков Apple, где обсуждалось использование метода класса, возвращает тип Self, но я не могу понять, как это сделать.

typealias JSONObject = AnyObject
protocol JSONParseable {
    static func fromJSONObject(jsonObject: JSONObject) throws -> Self
}

extension NSURL: JSONParseable {
    class func fromJSONObject(jsonObject: JSONObject) throws -> Self {
        guard let jsonString = jsonObject as? String else {
            throw JSONParseError.ConversionError(message: "blah")
        }
        guard let result = NSURL(string: jsonString) else {
            throw JSONParseError.ConversionError(message: "blah")
        }
        return result // Error: cannot convert return expression of type 'NSURL' to return type 'Self'
    }
}

Я нашел похожий вопрос, но ответ был в том, чтобы пометить класс как окончательный - я, очевидно, не могу сделать это в классе Foundation.

Может ли кто-нибудь объяснить, как исправить мой подход выше? Или предложить другой подход для добавления соответствия протоколу в классы Foundation?


person Rich Ellis    schedule 09.12.2015    source источник
comment
Да спасибо! Я выбрал подход self.init(...).   -  person Rich Ellis    schedule 10.12.2015
comment
не забудьте проголосовать, если вам понравился ответ.   -  person R Menke    schedule 10.12.2015


Ответы (1)


Используйте self.init(....) вместо NSURL(....), так как это также должно работать для NSURL подклассов.

protocol JSONParseable {
    static func fromJSONObject(jsonObject: JSONObject) throws -> Self
}

extension NSURL : JSONParseable {

    class func fromJSONObject(jsonObject: JSONObject) throws -> Self {

        guard let jsonString = jsonObject as? String else {
            throw JSONParseError.ConversionError(message: "blah")
        }
        guard let result = self.init(string: jsonString) else {
            throw JSONParseError.ConversionError(message: "blah")
        }
        return result
    }
}

Hack: определите typealias T, это вернет NSURL даже для подклассов.

protocol JSONParseable {
    typealias T = Self
    static func fromJSONObject(jsonObject: JSONObject) throws -> T
}

extension NSURL : JSONParseable {

    typealias T = NSURL
    class func fromJSONObject(jsonObject: JSONObject) throws -> T {

        guard let jsonString = jsonObject as? String else {
            throw JSONParseError.ConversionError(message: "blah")
        }
        guard let result = NSURL(string: jsonString) else {
            throw JSONParseError.ConversionError(message: "blah")
        }
        return result
    }
}

person R Menke    schedule 09.12.2015