在回答之前:
我知道:
URL
Employee
编写自定义解码器url
声明为String
我正在寻找一种更好的解决方案,用于解码可选的URL
本身。我希望我缺少一些Codable
魔术!
所以,我有JSON,例如
let json = Data("""
{
"name": "Fred",
"url": ""
}
""".utf8)
以及包含可选URL的相应对象...
struct Employee: Decodable {
let name: String
let url: URL?
}
由于JSON中的url
无效,我希望它解码为nil
,而不是抛出错误。
尝试以下操作无效(不会被调用)…
extension Optional where Wrapped == URL {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do {
self = try container.decode(URL.self)
} catch {
self = nil
}
}
}
过去我曾经用过……
struct FailableDecodable<T: Decodable>: Deodable {
let wrapped: T?
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do {
self.wrapped = try container.decode(T.self)
} catch {
print("Error decoding failable object: \(error)")
self.wrapped = nil
}
}
}
struct Employee: Decodable {
let name: String
let url: FailableDecodable<URL>?
}
但这需要我不断引用url.wrapped
。
有更好的解决方案吗?
答案 0 :(得分:5)
如果您使用的是Swift 5.1,则可以使用@propertyWrapper
:
let json = """
{
"name": "Fred",
"url": ""
}
""".data(using: .utf8)!
@propertyWrapper
struct FailableDecodable<Wrapped: Decodable>: Decodable {
var wrappedValue: Wrapped?
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
wrappedValue = try? container.decode(Wrapped.self)
}
}
struct Employee: Decodable {
let name: String
@FailableDecodable
private(set) var url: URL?
}
let employee = try! JSONDecoder().decode(Employee.self, from: json)
employee.url // nil