У меня есть некоторые объекты, structs
, которые я инициализирую из словарей JSON ([String : Any]
) с помощью функции init
, предоставленной из расширения протокола Decodable
(см. Инициируйте объект, соответствующий Codable, со словарем/массивом).
Итак, в основном у меня есть объекты, которые выглядят так:
struct ObjectModelA: Codable {
var stringVal: String
var intVal: Int
var boolVal: Bool
// Coding keys omitted for brevity
}
struct ObjectModelB: Codable {
var doubleVal: Double
var arrayOfObjectModelAVal: [ObjectModelA]
// Coding keys omitted for brevity
var complicatedComputedVar: String {
// expensive operations using the values in arrayOfObjectModelAVal
}
}
ObjectModelB
содержит массив ObjectModelA
, а также свойство, которое я действительно хочу установить, только если arrayOfObjectModelAVal
изменится.
Я могу использовать didSet
для arrayOfObjectModelAVal
, но это улавливает только будущие изменения свойства arrayOfObjectModelAVal
. Проблема в том, что я использую веб-сервис для извлечения данных JSON для создания массива ObjectModelB ([[String : Any]]
), и я создаю его следующим образом:
guard let objectDictArray = responseObject as? [[String : Any]] else { return }
let objects = objectDictArray.compactMap({ try? ObjectModelB(any: $0) })
Мои объекты создаются внутри замыкания compactMap
, а init
не вызывает didSet
.
Я также не могу «переопределить» инициализацию, предоставленную init
из протокола Decodable
(тот, что в закрытии: try? ObjectModelB(any: $0)
), потому что мой объект — это struct
, и это не наследование, это просто инициализатор, предоставленный протоколом. В противном случае я бы «переопределил» init
в своем объекте, а затем просто сделал бы super.init
, а затем какую-то функцию мутации, которая обновляет мое сложное свойство, и я бы сделал мое сложное свойство private(set)
.
Единственный другой вариант, который я могу придумать, — это создать ту мутирующую функцию, о которой я только что упомянул, и вызвать ее как в didSet
при изменении arrayOfObjectModelAVal
, так и затем обновить мой вызов инициализации объекта примерно так:
guard let objectDictArray = responseObject as? [[String : Any]] else { return }
let objects = objectDictArray
.compactMap({ try? ObjectModelB(any: $0) })
.forEach({ $0.updateProperties() })
Но теперь updateProperties
может быть вызван в любое время кем угодно (что плохо, потому что это очень утомительно), и нет никакой гарантии, что он будет вызван даже при создании массива объектов, потому что разработчик может забыть сделать часть forEach
. Поэтому мне нужен способ автоматического вызова функции updateProperties
сразу после инициализации объекта.