В swift, как мне вернуть объект того же типа, который соответствует протоколу
У меня есть следующий протокол
protocol JSONInitializable {
static func initialize(fromJSON: NSDictionary) throws -> Self?
}
Теперь я пытаюсь заставить эту функцию возвращать любой класс, соответствующий протоколу. Т.е. если у меня есть класс Foo
в соответствии с протоколом, я хочу вернуть Foo
объект из метода. Как я могу это сделать?
extension Foo: JSONInitializable {
static func initialize(fromJSON: NSDictionary) throws -> Foo? {
}
}
Я получаю ошибку:
Метод 'initialize' в не финальном классе 'Foo' должен возвращать 'Self', чтобы соответствовать протоколу 'JSONInitializable'
2 ответа
Автозаполнение поможет вам, но в основном, если Foo
это класс, вам просто нужен метод, который соответствует точной сигнатуре метода в вашем протоколе:
class Foo {}
protocol JSONInitializable {
static func initialize(fromJSON: [String : AnyObject]) throws -> Self?
}
extension Foo: JSONInitializable {
static func initialize(fromJSON: [String : AnyObject]) throws -> Self? {
return nil
}
}
Как примечание, вы должны в этом методе заменить все экземпляры Foo
с Self
, Если вы хотите использовать конструктор, он должен быть помечен как необходимый.
Имея это в виду, вероятно, имеет смысл изменить протокол на использование инициализатора, а не статического метода, называемого initialize
В таком случае взгляните на ответ Блейка Локли. Тем не менее, этот ответ стоит ответить на вопрос о том, как бороться с Self
в протоколах, так как, безусловно, есть случаи, когда нам может понадобиться метод, который возвращает Self
это не инициализатор.
Если Foo
это не класс, это тип значения, который не может быть подклассом, и поэтому мы возвращаем имя типа:
struct Foo: JSONInitializable {
static func initialize(fromJSON: [String : AnyObject]) throws -> Foo? {
return nil
}
}
enum Foo: JSONInitializable {
case One, Two, Three
static func initialize(fromJSON: [String : AnyObject]) throws -> Foo? {
return nil
}
}
Причина, по которой вам нужно вернуться Self?
от метода в случае класса из-за наследования. Протокол объявляет, что если вы соответствуете ему, у вас будет метод с именем initialize
чей тип возврата будет необязательной версией того, кем вы являетесь.
Если мы напишем Foo
"s initialize
метод, как вы это написали, то если мы подкласс Foo
с Bar
, то теперь мы нарушили наше соответствие протоколу. Bar
унаследовал соответствие с протоколом от Foo
, но у него нет метода, который вызывается initialize
и возвращается Bar?
, Есть тот, который возвращает Foo
,
С помощью Self
Здесь означает, что когда наши подклассы наследуют этот метод, он вернет любой тип. Self
является эквивалентом Свифта Objective-Cinstancetype
,
Как уже упоминалось в ответе nhgrif, измените тип возвращаемого значения Foo?
в self?
,
альтернативно
В Swift вы можете объявить init
s в протоколе, так что попробуйте что-то вроде этого:
protocol JSONInitializable {
init?(fromJSON: NSDictionary) throws
}
extension Foo: JSONInitializable {
required init?(fromJSON: NSDictionary) throws {
//Possibly throws or returns nil
}
}