首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用JSONEncoder将nil值编码为null

使用JSONEncoder将nil值编码为null
EN

Stack Overflow用户
提问于 2017-11-13 22:38:18
回答 4查看 15.9K关注 0票数 82

我使用的是Swift 4的JSONEncoder。我有一个带有可选属性的Codable结构,我希望这个属性在null值为nil时在生成的JSON值中显示为JSON值。但是,JSONEncoder会丢弃该属性,并且不会将其添加到JSON输出中。在这种情况下,有没有办法配置JSONEncoder使其保留密钥并将其设置为null

示例

下面的代码片段生成{"number":1},但我更希望它给我提供{"string":null,"number":1}

代码语言:javascript
复制
struct Foo: Codable {
  var string: String? = nil
  var number: Int = 1
}

let encoder = JSONEncoder()
let data = try! encoder.encode(Foo())
print(String(data: data, encoding: .utf8)!)
EN

回答 4

Stack Overflow用户

发布于 2020-06-11 03:51:54

下面是一种使用属性包装器的方法(需要Swift v5.1):

代码语言:javascript
复制
@propertyWrapper
struct NullEncodable<T>: Encodable where T: Encodable {
    
    var wrappedValue: T?

    init(wrappedValue: T?) {
        self.wrappedValue = wrappedValue
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch wrappedValue {
        case .some(let value): try container.encode(value)
        case .none: try container.encodeNil()
        }
    }
}

示例用法:

代码语言:javascript
复制
struct Tuplet: Encodable {
    let a: String
    let b: Int
    @NullEncodable var c: String? = nil
}

struct Test: Encodable {
    @NullEncodable var name: String? = nil
    @NullEncodable var description: String? = nil
    @NullEncodable var tuplet: Tuplet? = nil
}

var test = Test()
test.tuplet = Tuplet(a: "whee", b: 42)
test.description = "A test"

let data = try JSONEncoder().encode(test)
print(String(data: data, encoding: .utf8) ?? "")

输出:

代码语言:javascript
复制
{
  "name": null,
  "description": "A test",
  "tuplet": {
    "a": "whee",
    "b": 42,
    "c": null
  }
}

完整的实现在这里:https://github.com/g-mark/NullCodable

票数 27
EN

Stack Overflow用户

发布于 2020-03-21 18:00:24

这是我们在项目中使用的一种方法。希望能有所帮助。

代码语言:javascript
复制
struct CustomBody: Codable {
    let method: String
    let params: [Param]

    enum CodingKeys: String, CodingKey {
        case method = "method"
        case params = "params"
    }
}

enum Param: Codable {
    case bool(Bool)
    case integer(Int)
    case string(String)
    case stringArray([String])
    case valueNil
    case unsignedInteger(UInt)
    case optionalString(String?)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Bool.self) {
            self = .bool(x)
            return
        }
        if let x = try? container.decode(Int.self) {
            self = .integer(x)
            return
        }
        if let x = try? container.decode([String].self) {
              self = .stringArray(x)
              return
          }
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        if let x = try? container.decode(UInt.self) {
            self = .unsignedInteger(x)
            return
        }
        throw DecodingError.typeMismatch(Param.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Param"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .bool(let x):
            try container.encode(x)
        case .integer(let x):
            try container.encode(x)
        case .string(let x):
            try container.encode(x)
        case .stringArray(let x):
            try container.encode(x)
        case .valueNil:
            try container.encodeNil()
        case .unsignedInteger(let x):
            try container.encode(x)
        case .optionalString(let x):
            x?.isEmpty == true ? try container.encodeNil() : try container.encode(x)
        }
    }
}

用法是这样的。

代码语言:javascript
复制
RequestBody.CustomBody(method: "WSDocMgmt.getDocumentsInContentCategoryBySearchSource", params: [.string(legacyToken), .string(shelfId), .bool(true), .valueNil, .stringArray(queryFrom(filters: filters ?? [])), .optionalString(sortMethodParameters()), .bool(sortMethodAscending()), .unsignedInteger(segment ?? 0), .unsignedInteger(segmentSize ?? 0), .string("NO_PATRON_STATUS")])
票数 1
EN

Stack Overflow用户

发布于 2020-03-04 19:28:59

正如@Peterdk所提到的,已经创建了关于此问题的错误报告:

https://bugs.swift.org/browse/SR-9232

如果你想坚持这个特性应该如何在未来的版本中成为官方API的一部分,请随意投票支持它。

而且,正如Johan Nordberg在这篇错误报告中提到的,有一个库FineJson可以处理这个问题,而不必为所有的可编码结构重写每个encode(to:)实现^

下面的示例展示了我如何使用这个库在应用程序的后端请求的NULL有效负载中编码JSON值:

代码语言:javascript
复制
import Foundation
import FineJSON

extension URLRequest {

    init<T: APIRequest>(apiRequest: T, settings: APISettings) {

        // early return in case of main conf failure
        guard let finalUrl = URL(string: apiRequest.path, relativeTo: settings.baseURL) else {
            fatalError("Bad resourceName: \(apiRequest.path)")
        }

        // call designated init
        self.init(url: finalUrl)

        var parametersData: Data? = nil
        if let postParams = apiRequest.postParams {
            do {
                // old code using standard JSONSerializer :/
                // parametersData = try JSONSerializer.encode(postParams)

                // new code using FineJSON Encoder
                let encoder = FineJSONEncoder.init()

                // with custom 'optionalEncodingStrategy' ^^
                encoder.optionalEncodingStrategy = .explicitNull

                parametersData = try encoder.encode(postParams)

                // set post params
                self.httpBody = parametersData

            } catch {
                fatalError("Encoding Error: \(error)")
            }
        }

        // set http method
        self.httpMethod = apiRequest.httpMethod.rawValue

        // set http headers if needed
        if let httpHeaders = settings.httpHeaders {
            for (key, value) in httpHeaders {
                self.setValue(value, forHTTPHeaderField: key)
            }
        }
    }
}

这些是我为了处理这个问题而必须执行的唯一更改。

感谢Omochi的这个伟大的库;)

希望这能帮上忙。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47266862

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档