swift - 将无效 URL 解码为 nil
问题描述
在你回答之前:
我意识到:
- 空字符串是无效的
URL
- 我可以为它编写一个自定义解码器
Employee
- 我可以宣布
url
为String
我正在寻找的是解码可选URL
本身的更好解决方案。我希望Codable
我缺少一些魔法!
所以,我有 JSON 之类的
let json = Data("""
{
"name": "Fred",
"url": ""
}
""".utf8)
以及包含可选 URL 的相应对象……</p>
struct Employee: Decodable {
let name: String
let url: URL?
}
由于url
JSON 无效,我希望它解码为nil
,而不是抛出错误。
尝试以下不起作用(它不会被调用)......</p>
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
}
}
}
过去我用过……</p>
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
。
有更好的解决方案吗?
解决方案
如果您使用的是 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
编辑 - 可编码版本
如果您还需要顶级结构,Encodable
则可以使用Codable
对属性包装器的一致性。
@propertyWrapper
struct FailableDecodable<Wrapped: Codable>: Codable {
var wrappedValue: Wrapped?
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
wrappedValue = try? container.decode(Wrapped.self)
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(wrappedValue)
}
}
如果url
是,nil
这将输出一个 JSONurl: null
{"name":"Fred","url":null}
如果您希望在需要在其中实现自定义编码(使用)时不输出该url
属性(这将减轻使用属性包装器的好处)。nil
encode(to:)
Employee
注意:使用(未实现)的默认实现有效,但在isencode(to:)
时输出一个空对象:url
nil
{"name":"Fred","url":{}}
推荐阅读
- python - python for循环不会改变值
- typescript - 如何在 CodeBuild/Ubuntu (TS2307) 中使用 tsc 解析相对路径?
- angular - Angular/RxJS 手动更新管道主题(即使没有更改数据),“rxjs 管道中的单位转换”
- android - 在android应用程序中硬编码用户名和密码
- javascript - Jenkins CI E2E:不禁用量角器和硒指定的Firefox下载弹出窗口
- r - 在闪亮服务器上使用来自闪亮日志的 store_json() 的问题
- sql-server - 我们如何计算每天最后三天订购的唯一用户 ID?
- graphql - 在 apollo-client 的 useQuery 中使用 fetchPolicy='cache-and-network' 不会更新 fetch 上的缓存更多
- python - Selenium - 断言元素存在
- python - CV2,更改 .mp4 文件的编解码器?