【问题标题】:Creating model for JSON where key is a value为键是值的 JSON 创建模型
【发布时间】:2019-05-21 06:59:25
【问题描述】:

JSON

{  
    "rows" :
    [
        {
            "_id": "5cdc0ede5c3dcb04bdb3a972",
            "emp_code": 187,
            "log_id": 361711,
            "punch_time": "2019-05-07T04:00:33.000Z",
            "pin_type": 1,
            "status": 4,
            "__v": 0
        },
        {
            "_id": "5cdc40de5c3dcb04bdb3a972",
            "emp_code": 111,
            "log_id": 361701,
            "punch_time": "2019-05-07T04:00:35.000Z",
            "pin_type": 101,
            "status": 4,
            "__v": 0
        }
    ],
    "pin_type_text": {
        "1": "In Fingerprint",
        "4": "In Card",
        "101": "Out Fingerprint",
        "104": "Out Card"
    }
}  

每一行中pin_type的值是指pin_type_text中与其key对应的记录。

我正在使用 AlamofireObjectMapper 来创建模型,这里是 PinTypeText 模型:

class PinTypeText : Mappable {

    var inFingerprint: String?
    var inCard: String?
    var outFingerprint: String?
    var outCard: String?

    required init?(map: Map) {

    }

    func mapping(map: Map) {
        self.inFingerprint <- map["1"]
        self.inCard <- map["4"]
        self.outFingerprint <- map["101"]
        self.outCard <- map["104"]
    }  
}  

问题:假设将来 pin_type 值 - 1, 4, 101, 104 在后端发生变化,我如何在不改变模型的情况下处理这种情况.根据这个模型结构,每次后端模型更改时我都需要更改我的模型类

【问题讨论】:

  • 您可以使用Codable 容器来解析此类数据。
  • @PGDev :但是对于可编码的,我不需要在 JSON 中将变量命名为相同的名称,即 1,4,101,104 吗?这是不可能的命名约定。
  • 由于您的 JSON 由于版本迁移而更新,您可能希望创建两个模型来处理不同的 API 响应 JSON,然后您的 ObjectMapper 能够毫无问题地映射到不同的版本。例如PinTypeText_V1、PinTypeText_V2 继承自同一父模型 PinTypeText,使用 ObjectMapper 进行不同映射
  • @PeterGuo :但这需要每次后端发生变化时更新代码,不是吗?
  • @Nitish 添加了codable 的答案。看看吧。

标签: ios json swift objectmapper


【解决方案1】:

以下是您可以使用Codable 作为解决方案的方法,

1.创建一个模型Row,它将包含jsonrows数组中的单行数据,即

class Row: Decodable {
    var id: String?
    var pinType: String?
    var pinId: Int?

    enum CodingKeys: String, CodingKey {
        case id = "_id"
        case pinId = "pin_type"
    }
}

在上述模型中,我使用了 2 个不同的属性 - pinType and pinId

  1. pinId 将在row 中包含pin_type

  2. pinType 将包含对应于pinId 的实际值。我们稍后会填充这个值。

另外,我只使用了row 的一小部分键。您可以根据需要添加更多。

2.接下来创建另一个模型Response,它将包含Rowarray,即

class Response: Decodable {
    var rows: [Row]?

    enum CodingKeys: String, CodingKey {
        case rows, pin_type_text
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        rows = try values.decodeIfPresent([Row].self, forKey: .rows)
        let pinTypeText = try values.decodeIfPresent([String:String].self, forKey: .pin_type_text)
        rows?.forEach({ (row) in
            if let pinId = row.pinId {
                row.pinType = pinTypeText?[String(pinId)]
            }
        })
    }
}

在上述模型中,

  1. json 中的rows 数组被解析为[Row]

  2. pinTypeText dictionary 被解析为[String:String] 类型。

  3. 枚举[Row] 以使用pinIdpinTypeText dictionary 在每个row 中填充pinType

使用时,需要使用Row对象的pinType属性。

response?.rows?.forEach({ print($0.pinType) }) //This line will print - "In Fingerprint" and "Out Fingerprint"

如果您在实施此方法时遇到问题,请告诉我。

【讨论】:

    猜你喜欢
    • 2019-10-09
    • 2021-02-17
    • 1970-01-01
    • 2021-11-22
    • 1970-01-01
    • 2019-04-14
    • 2020-06-26
    • 2019-02-13
    • 1970-01-01
    相关资源
    最近更新 更多