Hi. I'm trying to create a variable that is a constant but I can't define the constant before super.init. So my question is this, is there a way to create a variable in my classes scope that becomes read only after I set a value?
as it stands, i know i can use "let myVariable = xxxx" - however, i need myVariable to be accesible through my entire project, not just one function.
to sum up my question in pseudo code...
let myVar: VALUETYPE
myFunction()
{
myVar = "value" // after this is set I want myVar to be read-only
}
myFunctionTwo()
{
print(myVar)
}
I think the best you can do is reduce the access level of its actual storage and vend it through a forwarding property that has only a getter and no setter:
private var _myVar: VALUETYPE?
public var myVar: VALUETYPE {
guard let defined = _myVar else {
preconditionFailure("Forgot to call “myFunction()” first.")
}
return defined
}
public func myFunction() {
precondition(_myVar == nil, "“myFunction()” called a second time.")
_myVar = "value"
}
// Warning: not thread safe, but if you're using this sort of initialization
// in a threaded context, you probably want to rethink your design anyway.
struct SingleSettable<T> {
private var _value: T?
public var value: T {
get {
guard let defined = _value else {
preconditionFailure("Forgot to set the value of this \(type(of: self))")
}
return defined
}
set {
precondition(_value == nil, "A \(type(of: self))'s value was set a second time")
_value = newValue
}
}
}
struct SomeTwoStageInitializedType {
let a, b, c: Int
var _d = SingleSettable<Int>()
var d: Int {
get { return _d.value }
set { _d.value = newValue }
}
init(a: Int, b: Int, c: Int) {
(self.a, self.b, self.c) = (a, b, c)
}
}
var x = SomeTwoStageInitializedType(a: 1, b: 2, c: 3)
//print(x.d) // Boom
x.d = 4
//x.d = 5 // Boom
I wish there was a less verbose to write:
var d: Int {
get { return _d.value }
set { _d.value = newValue }
}