swiftsingletonwatchos-3apple-watch-complication

CLKComplicationServer initializes an already initialized singleton class CLKComplicationDataSource, although init() is private


To update complications on the watch, I use a singleton class ComplicationController (irrelevant code has been omitted below):

final class ComplicationController: NSObject, CLKComplicationDataSource {

    static let shared = ComplicationController() // Instantiate the singleton

    private override init() {
        super.init()
        print("====self: \(self): init")
    } // Others can't init the singleton
}

The singleton is created on the watch by the extension delegate:

class ExtensionDelegate: NSObject, WKExtensionDelegate {

  override init() {
    super.init()
        _ = ComplicationController.shared           
  }
}

When I launch the watch extension with a breakpoint at the print statement above, the execution breaks and the stack trace is:
enter image description here

When I then execute the print statement in a single step, the debugger shows:

====self: <Watch_Extension.ComplicationController: 0x7bf35f20>: init  

When I then continue, the execution breaks again at the same breakpoint, and the stack trace is:
enter image description here

After another single step, the debugger shows:

====self: <Watch_Extension.ComplicationController: 0x7d3211d0>: init  

Obviously, the CLKComplicationServer has created another instance of the singleton.

My question is: Did I something wrong or is this a bug? If it is a bug, is there a workaround?

PS: It does not help not to initialize ComplicationController in the ExtensionDelegate. In this case, the 2nd instance is created as soon as ComplicationController.shared is used anywhere in the code.


Solution

  • I found a workaround:

    Do not instantiate the singleton in the app, i.e. do not use ComplicationController.shared anywhere.
    If you have to call functions in ComplicationController.shared, send a notification, e.g. to the default notification center.
    The ComplicationController singleton had to have registered for such notifications, and when it receives one, it has to execute the required function.
    This did work for me.