Swift Codable - Как сделать типы со ссылками друг на друга кодируемыми? - PullRequest
1 голос
/ 11 февраля 2020

Я получил два таких класса:

class Session {
  var name: String
  var data: [Double]
  var routes: [Route]

  init(named name: String, data: [Double] = [], routes: [Route] = []) {
    self.name = name
    self.data = data
    self.routes = routes
  }
}
class Route {
  var session: Session
  var startIndex: Int
  var endIndex: Int

  // A route stores only references to the real underlying data stored in a Session
  var data: [Double] { Array(session.data[startIndex...endIndex]) }

  init(session: Session, startIndex: Int, endIndex: Int) {
    self.session = session
    self.startIndex = startIndex
    self.endIndex = endIndex
  }
}

Обратите внимание, что объект Route не может быть инициализирован без соответствующего сеанса, он всегда зависит от него. Цель состоит в том, чтобы хранить в маршруте только ссылки на реальные данные, хранящиеся в объекте Session.

Во-первых, существует ли потенциальный цикл сохранения в этом шаблоне и как его разорвать, если он есть?

Второй вопрос: Я хочу сделать сеанс кодируемым. Проблема в том, что Session опирается на Route, а Route на Session. Я не могу сделать один Codable без создания другого, и я впадаю в бесконечное l oop.

Мне не обязательно требовать, чтобы Route соответствовал кодирование в качестве маршрута всегда будет зависеть от сеанса, пример JSON будет:

{
  "name": "Session Name"
  "data": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  "routes": [
    {
      "start_index": 3
      "end_index": 8
    }
    ...
  ]
}

Из этого я смогу восстановить сеанс из JSON.


Я пытался:

  • Использование nestedContainer, но требует, чтобы Route был Codable.
  • Соответствует Route к Codable, игнорируя сеанс, но я не могу, так как требуется декодер инициализатор для инициализации всех свойств. Я мог бы использовать значение по умолчанию session, а затем изменить его обратно на реальный сеанс, но это кажется неудобным и не очень надежным.
  • Определение декодера init с дополнительным сеансом аргумента, но я не могу получить доступ этот инициализатор после. Может быть, я могу расширить и перегрузить метод декодирования JSONDecoder, чтобы принять это во внимание?
  • Session is Identifiable, может быть, лучшее решение - это разделить Session и Route, назначив session_id для Route.

1 Ответ

1 голос
/ 11 февраля 2020

То, что вы смоделировали , является круговой зависимостью и не может быть представлено в JSON. Самым простым решением является изменение свойства session на маршруте.

weak var session: Session?

Это предотвращает сохранение цикла и делает его так, что сеанс не требуется в Route.init. С этим изменением вы можете затем l oop через все Route s в конце вашего Session инициализатора и назначить сеанс.

Недостатком этого решения является то, что вам нужно написать ваши собственные инициализаторы, но, похоже, вы все равно экспериментировали с этим.

...