Создание модели для JSON, где ключ является значением - PullRequest
1 голос
/ 21 мая 2019

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 , сопоставленной с ее ключом.

Я использую 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 изменятся в бэкэнде, как я могу обработать такой случай, не меняя мою модель. Согласно этой структуре модели, мне нужно менять класс модели каждый раз, когда меняется внутренняя модель

1 Ответ

2 голосов
/ 21 мая 2019

Вот как вы можете использовать Codable в качестве решения,

1. Создать модель Row, которая будет содержать данные одной строки в массиве rowsjson, то есть

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 будет содержатьЗначение pin_type в row

  2. pinType будет содержать фактическое значение, соответствующее pinId.Мы заполним это значение позже.

Кроме того, я использовал только небольшой набор клавиш row.Вы можете добавить больше по мере необходимости.

2. Затем создайте другую модель Response, которая будет содержать array из Row, то есть

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. rows в json анализируется как [Row].

  2. pinTypeText dictionaryанализируется как тип [String:String].

  3. [Row] перечисляется для заполнения pinType в каждом row с использованием pinId и pinTypeText dictionary.

При использовании необходимо использовать свойство pinType объекта Row.

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

Дайте мне знать, если у вас возникнут проблемы с реализацией этого подхода.

...