7

I'm having a smartwatch app on watchos2. The app always worked but now when it starts I immediately get this error:

Lop_WatchKit_Extension[17535:7854201] *********** ERROR -[SPRemoteInterface _interfaceControllerClientIDForControllerID:] clientIdentifier for interfaceControllerID:447E0002 not found

I found some topics here on stackoverflow but nothing solved the problem.

user1007522
  • 7,858
  • 17
  • 69
  • 113

5 Answers5

17

In my case, this was due to a retain cycle in one InterfaceController of mine.

If you get the logs similar to:

[default] -[SPRemoteInterface _interfaceControllerClientIDForControllerID:]:0000: ComF: clientIdentifier for interfaceControllerID:XXXXXXXX not found

&/or...

[default] _SendRecordedValues:000: ComF:<-Plugin controller ID XXXXXXXX has no client identifier

First, figure out which InterfaceController has the controller ID XXXXXXXX.

Have this in awake(withContext:)

override func awake(withContext context: Any?) {
    //...

    if let id = self.value(forKey: "_viewControllerID") as? NSString {
        let strClassDescription = String(describing: self)

        print("\(strClassDescription) has the Interface Controller ID \(id)")
    }

    //...
}

This logs:

[Target.Classname: 0xYYYYYYYY] has the Interface Controller ID XXXXXXXX

Once you identify the InterfaceController causing these logs, you can continue to debug.

It could be different in your case but in mine I had created a retain cycle with self in one of my closures within which took awhile to locate but I eventually broke the retain cycle with a [weak self] capture.

Basically, the error logs appear when an InterfaceController is trying to execute some code but it has already been released.


What I already had:

DispatchQueue.main.async {
    self.doSomethingThatDoesSomethingAsync()
}

What I fixed:

DispatchQueue.main.async { [weak self] in
    self?.doSomethingThatDoesSomethingAsync()
}
staticVoidMan
  • 19,275
  • 6
  • 69
  • 98
4

If you use didSet on any IBOutlets it will also throw this error in the logs.

class MyInterfaceController: WKInterfaceController {

  @IBOutlet var myLabel: WKInterfaceLabel! {
    didSet {
      myLabel.setTitle("Test")
    }
  }
nickromano
  • 918
  • 8
  • 16
1

How @nickromano sad, it's happens when you use didSet with IBOutlets. Cause it's calls before awake(withContext context: Any?) We can suppress this error if wrap it in DispatchQueue.main.async

@IBOutlet var statusLabel: WKInterfaceLabel! {
    didSet {
        DispatchQueue.main.async {
            self.statusLabel.setHidden(true)
        }
    }
1

This has happened to me a few times and more times than not, it is because of a timer that is still firing in a just-previously dismissed WKInterfaceController that I did not catch.

Best thing to do aside from comparing ID's like in @staticVoidMan's answer is to read the call stack. In my case I was able to identify that the old timer was still firing based off these hints:

8   Foundation                          0x00007fff214be867 __NSFireTimer + 67
9   CoreFoundation                      0x00007fff207a8e3f __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
10  CoreFoundation                      0x00007fff207a8912 __CFRunLoopDoTimer + 926

Here is the original call stack (for reference):

<MyApp.InterfaceController: 0x7fb3e4d2d020> has the Interface Controller ID 1EB00002
2021-05-26 14:44:06.632758-0600 MyApp WatchKit Extension[73392:3546879] [default] -[SPRemoteInterface _interfaceControllerClientIDForControllerID:]:2464: ComF: clientIdentifier for interfaceControllerID:1EB00007 not found. callStack:(
0   WatchKit                            0x00007fff38d1a268 -[SPRemoteInterface _interfaceControllerClientIDForControllerID:] + 220
1   WatchKit                            0x00007fff38d1bfff __54+[SPRemoteInterface setController:key:property:value:]_block_invoke + 340
2   WatchKit                            0x00007fff38d12323 spUtils_dispatchAsyncToMainThread + 30
3   WatchKit                            0x00007fff38d1be60 +[SPRemoteInterface setController:key:property:value:] + 179
4   WatchKit                            0x00007fff38d057af -[WKInterfaceObject _sendValueChanged:forProperty:] + 706
5   WatchKit                            0x00007fff38d2a5f8 -[WKInterfaceObject _setImage:forProperty:] + 50
6   MyApp WatchKit Extension          0x000000010955531d $s26MyApp_WatchKit_Extension25ActivityIndicatorDelegateC06handleE5TimeryyF + 813
7   MyApp WatchKit Extension          0x000000010955537a $s26MyApp_WatchKit_Extension25ActivityIndicatorDelegateC06handleE5TimeryyFTo + 42
8   Foundation                          0x00007fff214be867 __NSFireTimer + 67
9   CoreFoundation                      0x00007fff207a8e3f __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
10  CoreFoundation                      0x00007fff207a8912 __CFRunLoopDoTimer + 926
11  CoreFoundation                      0x00007fff207a7ec5 __CFRunLoopDoTimers + 265
12  CoreFoundation                      0x00007fff207a2546 __CFRunLoopRun + 1949
13  CoreFoundation                      0x00007fff207a18be CFRunLoopRunSpecific + 567
14  GraphicsServices                    0x00007fff25b49fd3 GSEventRunModal + 139
15  UIKitCore                           0x00007fff43290f24 -[UIApplication _run] + 917
16  UIKitCore                           0x00007fff43295c0b UIApplicationMain + 101
17  WatchKit                            0x00007fff38d0de65 WKExtensionMain + 800
18  libdyld.dylib                       0x00007fff20202db5 start + 1
19  ???                                 0x0000000000000001 0x0 + 1
)
David Villegas
  • 458
  • 3
  • 18
0

Have you changed the name of your module? If this is the case then you have to go through your storyboard and update it manually for all the Interfaces you have.

Edit with steps to fix:

Go to the storyboard and for each interface open the Identity inspector, then delete what's in Module and press enter, the new module should get auto-filled.

tonik12
  • 613
  • 1
  • 7
  • 25
  • The module field is empty on all of the interfacecontrollers. When I click on it and then just press delete ( but it's empty ) and then press and it still doesn't get auto filled in? – user1007522 Sep 21 '16 at 08:26
  • Do you have anything set under Project file -> Watch App target -> Build Settings -> Interface Builder Storyboard Compiler -> Default Module? I believe that should be the same as the one in the InterfaceController's. – tonik12 Sep 21 '16 at 08:34
  • It's filled in with the name of the group for example the group is called X WatchKit App and the module is X_WatchKit_App but is that oke? Do I need to check something else? – user1007522 Sep 21 '16 at 09:01
  • I filled in the X_WatchKit_App in the interface.storyboard all Controllers module. Now I get 1 the same error but also unable to find interface controller class .. to instantiate. – user1007522 Sep 21 '16 at 09:04