使用 JSONEncoders swift 跳过空字符串
Posted
技术标签:
【中文标题】使用 JSONEncoders swift 跳过空字符串【英文标题】:Skipping empty string with JSONEncoders swift 【发布时间】:2020-10-07 10:33:43 【问题描述】:我是一个可编码的序列化扩展,用于将我的 Codable 结构转换为字典,我面临的问题是字符串。我有时从 UITextField 获取字符串值,该值可能为空,因此会解码空字符串。如果值为空字符串,如何返回 nil。
extension Encodable
var requestDictionary: [String: Any]?
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
guard let data = try? encoder.encode(self) else return nil
return (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)).flatMap $0 as? [String: Any]
如果我有一个结构
let example = Exa(age: 10, name: "")
let dict = example.requestDictionary
print(dict)
我希望它只打印 ["age": 10]
并为空字符串返回 nil
【问题讨论】:
在Exa
init 中修复? self.name = name.isEmpty ? nil : name
。对了,为什么要先编码成 JSON,然后再解码成字典?
因为我正在使用可编码对象并使用字典参数进行 API 调用。
你不能在通用扩展中自定义,所以你必须在结构本身中进行自定义
是的,@Sh_Khan 你不能。
【参考方案1】:
你可以实现自己的String
编码方法扩展KeyedEncodingContainer
:
extension KeyedEncodingContainer
mutating func encode(_ value: String, forKey key: K) throws
guard !value.isEmpty else return
try encodeIfPresent(value, forKey: key)
顺便说一句,您的请求字典可以简化为:
extension Encodable
var dictionary: [String: Any]?
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
return try? JSONSerialization.jsonObject(with: encoder.encode(self)) as? [String: Any]
游乐场测试:
struct Exa: Encodable
let age: Int
let name: String
let example = Exa(age: 10, name: "")
let dict = example.dictionary!
print(dict) // "["age": 10]\n"
【讨论】:
当 String 属性不为空时失败,例如let example = Exa(age: 10, name: "Leo")
。 func encode
一直在无限循环中调用自己。
@MarioHuizinga 这真的很奇怪。不知道为什么会导致循环。
我已经在 Playground 上完全尝试过您的示例,只是更改了名称。你试过吗?似乎try encode(value, forKey: key)
语句再次(又一次)调用自身。
@MarioHuizinga 是的,我确实注意到了
我通过将 try encode
替换为 try encodeIfPresent
来修复您的解决方案。这可以防止递归。现在效果很好,感谢这个想法。我已经提交了对您的答案的修改。【参考方案2】:
我只是使用属性包装器来标记可以跳过哪些属性的另一种方法。
@propertyWrapper
struct SkipEmpty
var wrappedValue: String
extension SkipEmpty: Codable
init(from decoder: Decoder) throws
let container = try decoder.singleValueContainer()
self.wrappedValue = try container.decode(String.self)
func encode(to encoder: Encoder) throws
// nothing to do here, see below
但要真正跳过,您还需要为KeyedEncodingContainer.encode
类型的KeyedEncodingContainer.encode
方法创建重载:
extension KeyedEncodingContainer
mutating func encode(_ value: SkipEmpty, forKey key: K) throws
if !value.wrappedValue.isEmpty
try encode(value.wrappedValue, forKey: key) // encode the value here
您可以尝试使其更通用,例如SkipEmpty<T: Codable>
并为要跳过的值或谓词等提供另一个参数...
用法是:
struct Exa: Encodable
var age: Int
@SkipEmpty var name: String
【讨论】:
以上是关于使用 JSONEncoders swift 跳过空字符串的主要内容,如果未能解决你的问题,请参考以下文章