I have some objects, which are structs
, that I initialize from JSON dictionaries ([String : Any]
) via an init
function provided from an extension on the Decodable
protocol (see Init an object conforming to Codable with a dictionary/array).
So basically, I have objects that look like this:
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
contains an array of ObjectModelA
, and it also has a property which I only really want to set if the arrayOfObjectModelAVal
changes.
I can use a didSet
on arrayOfObjectModelAVal
, but that only catches future changes to the arrayOfObjectModelAVal
property. The problem is that I'm using a webservice to retrieve JSON data to create an array of ObjectModelB ([[String : Any]]
), and I build it like this:
guard let objectDictArray = responseObject as? [[String : Any]] else { return }
let objects = objectDictArray.compactMap({ try? ObjectModelB(any: $0) })
My objects get created inside the compactMap
closure, and init
doesn't trigger the didSet
.
I also can't "override" the init provided by the init
from the Decodable
protocol (the one in the closure: try? ObjectModelB(any: $0)
) because my object is a struct
and this isn't inheritance, it's just an initializer provided by a protocol. Otherwise, I'd "override" the init
in my object and then just do super.init
followed by some sort of mutating function that updates my complicated property and I'd make my complicated property private(set)
.
The only other option I can think of is creating that mutating function I just mentioned, and calling it in both the didSet
when arrayOfObjectModelAVal
changes, and then update my object initialization call with something like this:
guard let objectDictArray = responseObject as? [[String : Any]] else { return }
let objects = objectDictArray
.compactMap({ try? ObjectModelB(any: $0) })
.forEach({ $0.updateProperties() })
But now updateProperties
could be called at any time by anyone (which is bad because it's really taxing), and there's no guarantee that it even gets called when creating the array of objects because the dev could forget to do the forEach
part. Hence why I want a way to automatically call the updateProperties
function right after object initialization.