我无法掌握实例化变量的正确方法,这些变量总是需要在对象完全正常运行之前设置,但可能需要在构造函数之后进行实例化。根据Swift的其他约定和限制,似乎有一种我不知道的设计模式。
这是我的用例:
我的问题似乎是,子弹3中的两种方法都有缺陷。
在第一种情况下,只有一个合法的构造函数可以调用此类,但是我被迫覆盖其他构造函数并使用伪值初始化成员变量,即使其他构造函数从未打算使用(I我也试图根据Swift的最佳实践将这些变量保持为let
类型。
在第二种情况下,我实际上将构造函数分成两部分,并在第二部分在使用类之前无法调用时引入另一个失败点。我也无法将第二部分移动到一个保证在使用之前被调用的方法(例如viewDidLoad),因为我仍然需要从配置中传入其他参数。虽然我可以确保手动调用initPartTwo
,但我更倾向于使用一种机制来更好地将其与实际构造函数组合在一起。我不能成为第一个遇到这种情况的人,似乎有一种模式我没有看到让它变得更干净。
更新: 我最终选择了暗示模式的修改版本:
struct Thing {
let item1: String
let item2: String
struct Config {
let item3: String
let item4: String
}
var config:Config! {
willSet {
if self.config != nil {
fatalError("tried to initialize config twice")
}
}
}
init() {
self.item1 = ...
self.item2 = ...
...
}
public func phaseTwoInit(item3: String, item4: String) {
self.item3 = item3
self.item4 = item4
...
}
}
var t = Thing()
...
t.phaseTwoInit(...)
...
// start using t
答案 0 :(得分:1)
如果在对象初始化时不能提供初始实例变量属性值,通常将其声明为Optional。这样它就不需要由类的初始化程序初始化(它有一个值 - 它自动为nil
),而且你的代码随后可以区分未初始化(nil
)来自初始化(不是nil
)。
如果Optional是隐式展开的Optional,那么这种安排不需要对你的代码产生特别的影响(即它不必满足于unwrappings)。
如果你的反对意见是你被迫打开了这个实例变量的多个设置的大门,因为现在它必须用var
声明,然后用一个setter观察者关闭门:
struct Thing {
var name:String! {
willSet {
if self.name != nil {
fatalError("tried to set name twice")
}
}
}
}
var t = Thing()
t.name = "Matt" // no problem
t.name = "Rumplestiltskin" // crash