Я пишу протокол с именем JSONDataInitializable
, который позволит инициализировать значения из Data
, который содержит JSON с использованием JSONDecoder
.
Поскольку невозможно дляЯвно использовать дженерики в инициализаторах. Я объявил универсальный, независимый от типа вспомогательный метод в расширении протокола, который инициализатор позже вызывает.
Однако я придумал не один, а два способа написания такого метода.
(1):
private static func initialize<T: JSONDataInitializable>(from jsonData: Data) throws -> T {
return try JSONDecoder().decode(T.self, from: jsonData)
}
(2):
private static func initialize(from jsonData: Data) throws -> Self {
return try JSONDecoder().decode(Self.self, from: jsonData)
}
Не могли бы вы объяснить разницу между этими методами?Кажется, они оба дают один и тот же результат.
Единственное видимое отличие - это часть соответствия протокола в первом варианте.Однако методы объявлены в расширении протокола и поэтому доступны только для типов, которые соответствуют протоколу.
UPD
Вот полное описание протокола:
protocol JSONDataInitializable: Decodable {
init?(from jsonData: Data)
}
extension JSONDataInitializable {
init?(from jsonData: Data) {
do {
self = try Self.initialize(from: jsonData)
} catch {
print(error)
return nil
}
}
// (1)
private static func initialize<T: JSONDataInitializable>(from jsonData: Data) throws -> T {
return try JSONDecoder().decode(T.self, from: jsonData)
}
// ⬆⬆⬆
// OR
// ⬇⬇⬇
// (2)
private static func initialize(from jsonData: Data) throws -> Self {
return try JSONDecoder().decode(Self.self, from: jsonData)
}
}
Допустим, у нас есть структура с именем User
, то есть Decodable
.Нам нужно инициализировать значения User
из JSON (хранится как Data
).С протоколом инициализация работает так:
// Protocol conformance declaration
extension User: JSONDataInitializable { }
// JSON stored as Data
let networkData = ...
// Initialization
let john = User(from: networkData)