如何在解码 JSON 内容时 set/copy 构造 属性

How to set/copy Struct property while decoding JSON content

我有一个结构来解码 json 内容:

struct CustomResponse: Decodable {
var network: String
var weight: Int = 0
var pureWeight: Int

enum CodingKeys: String, CodingKey {
    case network = "network"
    case weight = "weight"
}}

我想设置从 JSON 解析到 pureWeight 属性 的初始 weight 值。即使后面改了weightpureWeight也应该是JSON响应过来的pureWeight

有什么简单的方法可以设置 pureWeight 一次(解析后)而不使用手动解码所有 json 内容?

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
...parsing all items one by one.
}

我使用了这段代码,但显然它总是返回重量的变异值:

 var pureWeight: Int {
    get {
        return weight
    }
 }

你可以像下面这样处理

保持 init:

import Foundation

let json = """
{
    "network" : "My Awesome network",
    "weight" : 100
}
"""

struct CustomResponse: Decodable {
    var network: String
    var pureWeight: Int

    // Computed
    var weight: Int {
        get {
            return hiddenWeight ?? pureWeight
        }
        set {
            hiddenWeight = newValue
        }
    }

    // Hidden from the outside world
    private var hiddenWeight: Int?


    enum CodingKeys: String, CodingKey {
        case network
        case weight
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        network = try container.decode(String.self, forKey: .network)
        pureWeight = try container.decode(Int.self, forKey: .weight)
    }
}

let jsonDecoder = JSONDecoder()
if let data = json.data(using: .utf8),
   var response = try? jsonDecoder.decode(CustomResponse.self, from: data) {

        print(response)
        response.weight = 200
        print(response)
}

所以这里要做的是,维护一个私有的属性,对外界隐藏。最初它被设置为 nil。从 JSON 解析时,它是 nil.

在获取 weight 属性 时我们隐藏 属性 hiddenWeightweight 以防 hiddenWeight 为零。

weight 设置为某项时,则设置 hiddenWeight

因此从下一次开始,每当请求 weight 时,都会返回 hiddenWeight

不使用 init:

如果要省略 init 实现,则必须使用除 weight 之外的任何其他 属性 名称。我正在使用 myWeight.

import Foundation

let json = """
{
    "network" : "My Awesome network",
    "weight" : 100
}
"""

struct CustomResponse: Decodable {
    var network: String
    var weight: Int

    // Computed
    var myWeight: Int {
        get {
            return hiddenWeight ?? weight
        }
        set {
            hiddenWeight = newValue
        }
    }

    // Hidden from the outside world
    private var hiddenWeight: Int?
}

let jsonDecoder = JSONDecoder()
if let data = json.data(using: .utf8),
   var response = try? jsonDecoder.decode(CustomResponse.self, from: data) {

        print(response)
        response.myWeight = 200
        print(response)
}

您仍然需要自定义 init,但最简单的方法是 let 声明初始权重 属性,因为它不应更改并将其设置在 init

struct CustomResponse: Decodable {
    var network: String
    var weight: Int
    let pureWeight: Int

    enum CodingKeys: String, CodingKey {
        case network = "network"
        case weight = "weight"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        network = try container.decode(String.self, forKey: .network)
        weight = try container.decode(Int.self, forKey: .weight)
        pureWeight = weight
    }
}