Search code examples
swiftinstantiationstatic-variables

iOS get stuck in instantiation dependency without failing


If I've something that looks like

class Foo {
  static shared = Foo()
  init() {
    print("init Foo")
    let _ = Bar.shared
  }
}

class Bar {
  static shared = Bar()
  init() {
    print("init Bar")
    let _ = Foo.shared
  }
}

// somwehere else:
let _ = Foo.shared

then the app gets stuck. Nothing happens. I understand that this design is wrong, but I'm wondering why the app is not crashing, reporting an error or at least printing a loop. The above code print

init Foo
init Bar

and that's it, showing that it is not looping but just getting stuck. An idea on what's happening?


Solution

  • In Swift, static type properties are initialized lazily, in a guaranteed thread-safe manner.

    NOTE in Type Properties

    Stored type properties are lazily initialized on their first access. They are guaranteed to be initialized only once, even when accessed by multiple threads simultaneously, and they do not need to be marked with the lazy modifier.

    This only once feature utilizes dispatch_once-like thing (or exactly itself) which needs mutual exclusion.

    When initializing Foo.shared, the lock for Foo.shared is locked. And while it's locked, Bar.shared needs to be initialized, so the lock for Bar.shared is locked. And while both locked, Foo.shared needs to be initialized, but the lock for it is already locked, so wait there till the lock is freed...

    We call this situation a dead-lock.