gpt4 book ai didi

swift - 在 Swift 中,如何在对象创建后立即调用函数

转载 作者:行者123 更新时间:2023-11-30 11:24:56 25 4
gpt4 key购买 nike

我有一些对象,它们是结构,我通过 init 函数从 JSON 字典 ([String : Any]) 初始化它们由 Decodable 协议(protocol)的扩展提供(请参阅 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 更改时才设置该属性。

我可以在 arrayOfObjectModelAVal 上使用 didSet,但这只能捕获对 arrayOfObjectModelAVal 属性的 future 更改。问题是我正在使用 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

我也无法“覆盖”由 Decodable 协议(protocol)中的 init 提供的 init(闭包中的那个:try? ObjectModelB(any : $0)) 因为我的对象是一个 struct 并且这不是继承,它只是协议(protocol)提供的初始化程序。否则,我会“覆盖”对象中的 init ,然后执行 super.init ,然后执行某种变异函数来更新我的复杂属性,然后我会将我的复杂属性设置为private(set)

我能想到的唯一其他选择是创建我刚才提到的变异函数,并在 arrayOfObjectModelAVal 更改时在 didSet 中调用它,然后更新我的对象初始化调用如下:

guard let objectDictArray = responseObject as? [[String : Any]] else { return }
let objects = objectDictArray
.compactMap({ try? ObjectModelB(any: $0) })
.forEach({ $0.updateProperties() })

但是现在 updateProperties 可以被任何人随时调用(这很糟糕,因为它真的很费力),并且不能保证它甚至在创建对象数组时会被调用,因为开发人员可以忘记执行 forEach 部分。因此,为什么我想要一种在对象初始化后立即自动调用 updateProperties 函数的方法。

最佳答案

我找到了一种使用工厂方法来完成此任务的方法。就像我在原来的问题中所说的那样,我想要使用的初始化器是由 Decodable 上的协议(protocol)扩展提供的。 (参见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)
}
}

现在如果我定义一个initObjectModelB具有与 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()
}
}

这似乎有效。我喜欢它,因为如果我不添加 initDecodable 中提供的完全匹配扩展名,那么我的对象仍然可以使用 Decodable 中提供的扩展名扩大。但如果我确实提供自己的,我只需使用 createFrom工厂方法使用 init 创建我的类型的实例来自Decodable ,然后做我想做的其他事情。通过这种方式,我可以控制哪些对象需要特殊的初始化处理,哪些不需要,但在创建对象时,没有任何变化。你还是用同样的init(any:)功能。

关于swift - 在 Swift 中,如何在对象创建后立即调用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50846825/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com