首页 > 解决方案 > Swift:仅发布特定的可编码对象

问题描述

我正在尝试解决如何通过 put 请求仅上传某些值。本质上,我有一个应用程序,当用户访问特定屏幕时,会有一堆字段,其中一些值将从 API 预先填充(确切地说,哪些值已经填充是不可预测的)。任何空白字段都是可编辑的,用户可以将自己的值放入并通过放置请求上传。但是,我只想上传新值(在原始 API 响应中基本上是“nil”)。我不想覆盖初始响应附带的值并“重新上传”它们。这是实质上代表请求主体的可编码结构:

struct UpdateRequest: Codable {

        let total: Double?
        let discrep: Double?
        let percent: Double?
        let pre: Double?
        let target: Double?
        let req: Double?
        let dep: Double?
    }

所以所有值都是可选的。

这是我的更新方法,一旦用户完成“空白”并按下特定按钮,就会调用它:

    func updateVals() {
        let args = ["id": viewModel.id]

        guard let body = convertValues() else { return }

        API.client.post(.order, with: args, using: .put, posting: body, expecting: MessageResponse.self) { (success, response) in

            switch success {
            case .failure:
                DispatchQueue.asyncMain {
                    let viewController = WarningViewController.detailsUpdatedFailure()
                    self.present(viewController, animated: true, completion: nil)
                }
            case .success:
                DispatchQueue.asyncMain {
                    let viewController = WarningViewController.detailsUpdatedSuccess()
                    self.present(viewController, animated: true, completion: nil)
                }
            }
        }
    }
}

这是 convertValues() :

func convertValues() -> UpdateRequest? {

      // In here I have a bunch of logic to convert values to specific units which is not relevant to this question

    {

        return UpdateRequest(
           total: convertedTotal
           discrep: convertedDiscrep
           percent: convertedPercent
           pre: convertedPre
           target: convertedTarget
           req: convertedReq
           dep: convertedDep
           )
    }

    return nil
}

但是,如果“total”例如在初始 API 响应中,我不想将其上传到此请求 - 因为此端点与我从中填充这些初始值的“get”端点基本相同。

显然,我可以编写逻辑来检查值是否在响应中,但是我怎样才能只将新值上传到此 UpdateRequest 而不会为我不需要的值上传“nil”值?

标签: swiftxcodeapicodable

解决方案


您需要做的就是覆盖encode(to:)UpdateRequest使用encodeIfPresent,因为该方法不会包含 nil 值。

func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encodeIfPresent(total, forKey: .total)
    try container.encodeIfPresent(discrep, forKey: .discrep)
    //... and so on
}

total仅设置示例

let req = UpdateRequest(total: 123.5, discrep: nil, percent: nil, pre: nil, target: nil, req: nil, dep: nil)

do {
    let data = try JSONEncoder().encode(req)
    print(String(data: data, encoding: .utf8))

} catch {
    print(error)
}

输出

可选(“{\”总计\“:123.5}”)


推荐阅读