如何防止在 api 更改时解码/编码时丢失密钥?

问题描述

以下情况: 我使用了几个使用数据结构的设备。如果我现在为较新版本扩展结构的键,则对新结构进行编码然后进行同步。作为同步的结果,旧数据结构用于解码。当您随后与新设备同步时,新密钥已丢失。我怎样才能防止这种情况?

enter image description here

使用游乐场

import Foundation

struct OLD_API: Codable {
  var text: String
}

struct NEW_API: Codable {
  var text: String
  let value: Int
}

// Init data on device with NEW data struct
var newDevice = NEW_API(text: "Dog",value: 200)
let data = try! JSONEncoder().encode(newDevice)

// .. sync to other devices (new to old)

// modified data on device with OLD data struct
var oldDevice = try! JSONDecoder().decode(OLD_API.self,from: data)
oldDevice.text = "Cat"
let newData = try! JSONEncoder().encode(oldDevice)

// .. sync to other devices (old to new)

// decode data on device with NEW data struct
newDevice = try! JSONDecoder().decode(NEW_API.self,from: newData)
print(newDevice)

解决方法

用 do catch 包裹你的最后一条 decode 语句,你会发现发生了什么

  do {
   newDevice = try JSONDecoder().decode(NewApi.self,from: newData)
} catch {
   print(error)
}

错误将是这样的 keyNotFound(CodingKeys(stringValue: "value",intValue: nil),Swift.DecodingError.Context(codingPath: [],debugDescription: "No value associated with key CodingKeys(stringValue: "value",intValue: nil) ("value" )”,底层错误: nil))

您可以做的一件事是创建自定义解码器初始化程序

 init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    text = try container.decode(String.self,forKey: .text)
    value = (try? container.decode(Int.self,forKey: .value) ) ?? 0
}

并为“value”属性提供默认值(如果未找到)

我建议您将此说服 init 移至“NewApi”结构的扩展,以免丢失默认初始化程序。