微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

可解码属性包装器的自动可解码合成

如何解决可解码属性包装器的自动可解码合成

假设我有可解码的属性包装器:

@propertyWrapper
struct OptionalDecodable<Value: Decodable>: Decodable {
  var wrappedValue: Value?
}

编译器确实为以下内容合成了init

struct Model: Decodable {
  @OptionalDecodable private(set) var string: String?
}

为了测试这是否有效,我只是尝试解码空的 JSON(即“{}”)

但是,string 属性不被视为可选属性,即当没有 string 键时,我会收到未找到键的错误

有办法解决这个问题吗?

解决方法

我不确定这是否是最好的方法,但问题是属性包装器的 wrappedValue 类型必须与属性的类型匹配,而 String 与 {{1} 不同}.

克服此问题的一种方法是使属性包装器通用,但以允许您从 String?String 初始化类型的方式进行限制:

Int
protocol ExpressibleByString {
    init(fromString: String)
}
extension String: ExpressibleByString {
    init(fromString: String) { self = fromString }
}
extension Optional: ExpressibleByString where Wrapped == String {
    init(fromString: String) { self = fromString }
}

然后您可以在可选和非可选 @propertyWrapper struct IntOrString<V: ExpressibleByString & Decodable>: Decodable { var wrappedValue: V } extension IntOrString { init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() do { let int = try container.decode(Int.self) wrappedValue = .init(fromString: int.description) } catch DecodingError.typeMismatch { wrappedValue = try .init(fromString: container.decode(String.self)) } } } extension KeyedDecodingContainer { func decode<V: ExpressibleByNilLiteral>(_ t: IntOrString<V>.Type,forKey key: K) throws -> IntOrString<V> { if let v = try decodeIfPresent(t,forKey: key) { return v } return IntOrString(wrappedValue: nil) } } 上使用它:

String

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。