By Drewag in his answer to the question
Every member constant must have a value by the time initialization is complete. Sometimes, a constant cannot be initialized with its correct value during initialization, but it can still be guaranteed to have a value before being accessed.
Using an Optional variable gets around this issue because an Optional is automatically initialized with nil and the value it will eventually contain will still be immutable. However, it can be a pain to be constantly unwrapping a variable that you know for sure is not nil. Implicitly Unwrapped Optionals achieve the same benefits as an Optional with the added benefit that one does not have to explicitly unwrap it everywhere.
The following code defines two classes, Country
and City
, each of which stores an instance of the other class as a property. Every country must have a capital city and every city must always belong to a country.
class Country {
let name: String
var capitalCity: City! //why I can't use let!
init(name: String, capitalName: String){
self.name = name
self.capitalCity = City(name: capitalName, country: self)
}
deinit {
print("\(name) has been de-initialized the city \(capitalCity.name) is gone with with the country")
}
}
class City{
let name: String
unowned let country: Country
init(name: String, country: Country){
self.name = name
self.country = country
}
deinit {
print("The city \(name) has been de-initialized ")
}
}
var country = Country(name: "Canada", capitalName: "Ottawa")
}
However, if I changed the line var capitalCity: City!
into let capitalCity: City!
, the compiler given out the following error warning.
Question: Isn't that we can use Implicitly Unwrapped Optional when a constant that cannot be defined during initialization? What's the error here?
The important part is here:
City(name: capitalName, country: self)
You are definitely using self
in the expression which is executed before the assignment to the property capitalCity
.
If you want to use self
in any of the expressions, it needs to be in the second phase of two phase initialization, which means all properties needs to be initialized before the usage of self
.
With using var
, Swift assigns a default initial value nil
for the property capitalCity
. So the property can be considered as "already initialized", so, you can use self
after you have initialized another property name
.
(You know giving nil
to a let-constant of ImplicitlyUnwrappedOptional
is ridiculous.)
By the way private(set) var
is often used in similar cases:
private(set) var capitalCity: City!