Reputation: 3956
I have two singleton classes. I have implemented the code in Playground. Code is as below
//: Playground - noun: a place where people can play
import UIKit
class A {
private init() {
print("1")
setB()
print("2")
}
static let a = A()
func setB() {
_ = B.b
}
}
class B {
private init() {
setA()
}
static let b = B()
func setA() {
print("3")
_ = A.a // Doesn't execute beyond this
print("4")
}
}
_ = A.a
I am creating Class A
object outside, which in turn creates object of Class B
. Since A
is singleton, object is already created. Then inside constructor of B
i am accessing the object of A
. But code doesn't execute beyond that line. Output of the above code is
1
3
Can anyone help me understand what is wrong with the code? I want to know why it stops executing. There are no syntax errors/warnings.
Upvotes: 0
Views: 89
Reputation: 73196
Since A is singleton, object is already created.
Not correct. Static properties are lazy per default. This means that neither A.a
not B.b
will be instantiated until they are first used. This is just a detail though, as any attempt to initialize A.a
will lead to attempting to re-access the static property before its initialization has completed (leading, most likely, to a threading deadlock).
When you invoke _ = A.a
you will start a call-chain that ends in an attempt to get a reference of A.a
before it has finished its initialization.
// instantiate A.a
_ = A.a
// -> calls init() of A
// -> calls setB() of A
// -> instantiates B.b
// -> calls init() of B
// -> calls setA() of B
// -> tries to grab a reference to A.a, but the
// initialization of A.a has not yet finished!
// (as you can see by the lack of printing "2").
I don't exactly know what this would imply (undefined behavior?), but possibly, since initialization of A.a
is yet to finish, the access of A.a
in setA()
of B
will believe it is time to instantiate A.a
, re-starting the call-chain that ends, again, with an attempt to access A.a
before it has been initialized; leading to a recursive call-chain loop (which will "freeze" and eventually crash the playground).
Another probably more plausible scenario, as pointed out my @MartinR below, is that we don't actually enter a recursive call-chain but rather a threading deadlock (due to the thread-safety of static properties), as soon as we try to access A.a
before it has been fully initialized.
In any case, the core issue is attempting to access A.a
before it has fully completed its initialization.
Upvotes: 3