在Swift/iOS中使用前初始化类属性
我很难掌握实例化变量的正确方法,这些变量总是需要在对象完全运行之前设置,但可能需要在构造函数之后实例化。基于Swift的其他约定和限制,似乎有一种设计模式我不知道 以下是我的用例:在Swift/iOS中使用前初始化类属性,ios,swift,Ios,Swift,我很难掌握实例化变量的正确方法,这些变量总是需要在对象完全运行之前设置,但可能需要在构造函数之后实例化。基于Swift的其他约定和限制,似乎有一种设计模式我不知道 以下是我的用例: 我有一个从UIViewController继承的类,它将基于用户操作以编程方式创建视图 我需要将这些视图附加到此类,但要这样做,我需要根据另一个控制器提供的配置数据检索它们的内容 我不在乎这个配置数据是传递给构造函数(在这种情况下,它总是必需的)还是在使用它之前通过对这个对象的二次调用提供的 我的问题似乎是子弹3
- 我有一个从UIViewController继承的类,它将基于用户操作以编程方式创建视图
- 我需要将这些视图附加到此类,但要这样做,我需要根据另一个控制器提供的配置数据检索它们的内容
- 我不在乎这个配置数据是传递给构造函数(在这种情况下,它总是必需的)还是在使用它之前通过对这个对象的二次调用提供的
let
类型)
在第二种情况下,我有效地将构造函数分为两部分,并引入一个额外的失败点,以防在使用类之前调用第二部分失败。我也不能将第二部分移到保证在使用之前调用的方法(例如viewDidLoad),因为我仍然需要从配置中传入其他参数。虽然我可以确保手动调用initPartTwo
,但我更希望有一种机制能够更好地将其与实际构造函数分组。我不可能是第一个遇到这种情况的人,似乎有一种模式我没有看到,使这个更干净
更新:
我最终选择了matt建议的模式的修改版本:
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
如果在对象初始化时无法提供初始实例变量属性值,通常的做法是将其声明为可选。这样,它就不需要由类的初始值设定项初始化(它有一个值-它自动为
nil
),另外,您的代码随后可以区分未初始化(nil
)和已初始化(而不是nil
)
如果是可选的,如果是隐式展开的可选,则此安排不需要对代码产生特殊影响(即,它不必添加展开)
如果您的反对意见是,由于现在必须使用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
请参阅我的书的第二部分,其中我讨论了如何“延迟变量的初始化”,但是所有对该变量的引用都必须使用问号。实际上,以相同方式(但在不同时间)实例化的两个变量的访问方式将非常不同。这真的是最佳解决方案吗?如果这些是隐式展开的选项,则不是。如果您有疑问,您仍然可以检查
nil
,但您可以不带问号和感叹号地引用它们。请尝试实际阅读我向您介绍的书中的部分。我用例子讨论了所有这些。我读过它,我喜欢你描述的隐式解包可选解决方案,但我仍然有点困惑,因为它似乎与斯威夫特的另一个咒语/惯例相矛盾,即总是使用let
来声明不会更改的变量。对于隐式可选变量,我必须使用var
,即使我只设置了一次变量(尽管不是在构造函数中)。这似乎有些奇怪,因为Swift-even特意对使用let
声明的常规成员变量做了这样的例外,允许它们在init
完成之前保持nil
,所以我很惊讶隐式展开的选项与let
不兼容