0

Following situation: I use several devices that use a data struct. If I now expand the keys of the structure for newer versions, the new structs are encoded and then synchronized. As a result of the synchronization, the old data struct is used for decoding. When you then synchronize with the new devices, the new keys have been lost. How can I prevent this?

enter image description here

Use playground

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)
Stefan
  • 190
  • 1
  • 11
  • 1
    This is an good question -- however, please post code, not pictures of code, which are not searchable, not copy/pastable, and don't work well on mobile devices or with screen readers. – jnpdx Jun 04 '21 at 21:40
  • Of course they are lost because the old API doesn’t know about the new keys. You could declare the new keys as optional. And I totally agree with jnpdx. – vadian Jun 04 '21 at 21:45
  • @jnpdx code was added. – Stefan Jun 04 '21 at 22:21
  • Unfortunately, optional keys are not a solution. I want to avoid losing the information. @vadian – Stefan Jun 04 '21 at 22:21
  • This is not possible if you encode the data with the old API which just drops the *new* keys. – vadian Jun 05 '21 at 04:14
  • i agree with vadian new key will drop. i find related question it read all the key and value but that not create model successfully yet. se here : https://stackoverflow.com/questions/67403056/swift-what-is-the-simplest-modern-approach-for-anonymizing-json-content-while?noredirect=1#comment119281721_67403056 –  Jun 05 '21 at 04:43
  • I am currently working with dictionaries. to read I decode. when I write, I manipulate the multidimensional dictionary. I think it should keep the original json and merge the new data. what do you think? – Stefan Jun 05 '21 at 11:44

1 Answers1

-1

Wrap your last decode statement with do catch and you will discover what is going on

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

error will be something like this keyNotFound(CodingKeys(stringValue: "value", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: "value", intValue: nil) ("value").", underlyingError: nil))

one thing you can do is create a custom decoder initializer

 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
}

and provide a default value for "value" property if it's not found

I suggest you move this convince init to an extension of "NewApi" struct to not lose a default initializer.

Salah Amassi
  • 132
  • 2
  • 8
  • The problem is not that the code above crashed, but that the data was lost. If I create a new value in my app, which the user enters, it is deleted when it is synchronized with the old device. So the question is, how can I synchronize with old devices without losing the new key with the values. – Stefan Jun 04 '21 at 22:40