使用 JSONEncoders 跳过空字符串 swift

Skipping empty string with JSONEncoders swift

我是一个 Codable 序列化扩展,我用它来将我的 Codable 结构转换为字典,我面临的问题是字符串。我有时会从 UITextField 中获取字符串值,该值可能为空,因此会解码一个空字符串。如果值为空字符串,我如何 return 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 { [=11=] as? [String: Any] }
    }
}

如果我有一个结构

let example = Exa(age: 10, name: "")
let dict = example.requestDictionary
print(dict)

我希望它只为空字符串打印 ["age": 10] 和 return nil

我只是另一种方法,使用 属性 包装器来标记哪些属性可以被跳过。

@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
   }
}

但要真正跳过,您还需要为 SkipEmpty 类型的 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
}

您可以实现自己的 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"