我有一些structs
的对象,我通过[String : Any]
协议上的扩展提供的init
函数从JSON字典(Decodable
)初始化(见Init an object conforming to Codable with a dictionary/array)。
基本上,我的对象看起来像这样:
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
属性的未来更改。问题是我正在使用Web服务来检索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
协议提供的init(闭包中的那个:try? ObjectModelB(any: $0)
),因为我的对象是{{1}这不是继承,它只是协议提供的初始化程序。否则,我会“覆盖”我的对象中的struct
,然后执行init
,然后执行一些更新我复杂属性的变异函数,然后创建复杂的属性{{1} }。
我能想到的唯一另一个选择是创建我刚刚提到的变异函数,并在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
函数的方法。
答案 0 :(得分:0)
我想出了一种使用工厂方法实现此目的的方法。就像我在原始问题中所说的那样,我想要使用的初始化程序由Decodable
上的协议扩展提供(参见Init an object conforming to Codable with a dictionary/array)。我继续在createFrom
扩展名中添加Decodable
静态函数,如下所示:
extension Decodable {
init(any: Any) throws {
// https://stackoverflow.com/questions/46327302
}
static func createFrom(any: Any) throws -> Self {
return try Self.init(any: any)
}
}
现在,如果我在init
上定义一个ObjectModelB
,其功能签名与init
扩展程序中提供的Decodable
相同,就像这样:
struct ObjectModelB: Codable {
var doubleVal: Double {
didSet {
computeComplicatedVar()
}
}
var arrayOfObjectModelAVal: [ObjectModelA] {
didSet {
computeComplicatedVar()
}
}
// Coding keys omitted for brevity
private(set) var complicatedVar: String = ""
mutating private func computeComplicatedVar() {
// complicated stuff here
}
init() {
doubleVal = 0.0
arrayOfObjectModelAVal = []
}
init(any: Any) throws {
self.init()
self = try ObjectModelB.createFrom(any: any)
computeComplicatedVar()
}
}
这似乎有效。我喜欢它,因为如果我没有添加与init
扩展程序中提供的Decodable
完全匹配的Decodable
,那么我的对象仍然可以使用createFrom
扩展名中提供的对象。但是,如果我提供自己的,我只使用init
工厂方法使用Decodable
中的init(any:)
创建我的类型的实例,然后在此之后执行我想要的任何其他操作。这样,我控制哪些对象需要特殊的初始化处理,哪些对象不需要,但是在创建对象时,没有任何变化。您仍然使用相同的geom_bar
函数。