#json #swift #xcode #generics #swift5
#json #swift #xcode #общие #swift5
Вопрос:
Я работаю над небольшой структурой, которая обрабатывает синтаксический анализ JSON. До сих пор все работало, за исключением того, что я хочу передать пользовательскую структуру в качестве структуры для использования при декодировании, JSONDecoder().decode(type.self, from: data)
но это выдает следующую ошибку:
Не удается преобразовать значение типа ‘Codable’ (он же ‘Decodable amp; Encodable’) в ожидаемый тип аргумента ‘T.Тип’
private func parseJson(data: Data, type: Codable) -> Codable? {
do {
let decoded = try JSONDecoder().decode(type.self, from: data)
return decoded
} catch {
print("JSON decode error: (error.localizedDescription)")
}
return nil
}
Есть ли способ, которым я могу передать структуру в этот метод для использования в качестве типа для decode()
функции? Если я напрямую задаю тип, который я пытаюсь передать в функцию в функции decode (), код работает как ожидалось, он выдает ошибку только при попытке его передать.
Ответ №1:
Что вам нужно, так это универсальный метод:
private func parseJson<T: Decodable>(data: Data, type: T.Type) -> T? {
do {
return try JSONDecoder().decode(type.self, from: data)
} catch {
print("JSON decode error:", error)
return nil
}
}
Вы также можете опустить тип и явно задать тип результирующего объекта:
private func parseJson<T: Decodable>(data: Data) -> T? {
do {
return try JSONDecoder().decode(T.self, from: data)
} catch {
print("JSON decode error:", error)
return nil
}
}
Тестирование игровой площадки:
struct User: Codable {
let id: Int
let name: String
}
let user: User = .init(id: 2, name: "abc")
let userData = try! JSONEncoder().encode(user)
let decodedUser: User = parseJson(data: userData)!
decodedUser.name // "abc"
Примечание: я возвращаю необязательные типы, но вы обязательно должны заставить свои методы выдавать и возвращать необязательные, как вы можете видеть ниже, где я расширяю данные:
extension Data {
func decodedObject<T: Decodable>() throws -> T {
try JSONDecoder().decode(T.self, from: self)
}
}
do {
let decodedUser: User = try userData.decodedObject()
print(decodedUser.name) // "abc"
} catch {
print(error)
}
Комментарии:
1. Кажется, это работает, но я не совсем понимаю, как, не могли бы вы объяснить это немного подробнее?
2.
Codable
это не тип, это протокол.T
является универсальным типом, который должен соответствоватьDecodable
3. Второе решение для меня не работает. Он выдает
Cannot explicitly specialize a generic function
ошибку.