WatchKit: unable to find interface controller class

笑着哭i 提交于 2019-11-28 06:48:04

I got this error after renaming the WatchKit target, but finally realized: if you rename your WatchKit targets, you'll have to go through the interfaces in Interface Builder and make sure the module names for each of them is renamed as well.

You can do this by selecting an interface controller, clicking the Identity Inspector (or command-option-3), delete the module name, then tab away. It will automatically be filled in with the new target name. That did it for me!

This error came up for me because I was not properly handling the didDeactivate message. My deactivated controller was still receiving messages via MMWormhole. Once I severed that connection, the error went away. It turns out that in the simulator all the deactivated interface controllers hang around in memory, so you have to carefully make sure they don't get any more messages of any kind. I don't know if this happens on the Watch itself, but of course we should assume so.

I spent way too much time with this issue, but finally figured what it was. The Apple Watch has basically two navigation patterns:

Hierarchical:

[self pushControllerWithName:@"controllerName" context:nil];

Page-based:

[[self class] reloadRootControllersWithNames:@[@"controller1",@"controller2"] contexts:nil];

According to apple:

You cannot combine hierarchical and page-based interface styles. At design time, you must choose the style that best suits your app’s content and design for that style.

So, the issue is that I was mixing both and that leads to undefined behavior like:

*********** ERROR -[SPRemoteInterface _interfaceControllerClientIDForControllerID:] clientIdentifier for interfaceControllerID:(null) not found

Hope this helps other developers

EDIT:

Just a suggestion that worked for me as a workaround, when using Page-based navigation you can still present modal controllers (just saying):

[self presentControllerWithName:@"controllerName" context:nil];
Senseful

This bug seems to be closely related to this one: Unable to see custom classes in Interface Builder drop down.

When I originally tried solving this, I had to manually type in the module name since the drop down was empty for both the custom classes and the module names.

Examining the storyboard's source code reveals one workaround.

Interface controllers that work look like this:

<controller id="AgC-eL-Hgc" customClass="InterfaceController" 
  customModule="myWatchApp_WatchKit_App" customModuleProvider="target">

Interface controllers that don't work lack the customModule and/or the customModuleProvider attribute(s).

Therefore, a workaround is to manually add those missing attributes to the storyboard file by right-clicking it and choosing Open As > Source Code.

A longer-term solution may be to fix the storyboard so that custom classes appear in the drop downs (see linked question for some potential fixes).

Update:

Other interface controllers that also work use customModule="myWatchApp_WatchKit_Extension" (notice the _Extension vs. _App difference) and don't need the customModuleProvider attribute.

For me, this appears to be a false negative. I tried all suggested solutions, but then proved it's an Apple error by creating a brand new Apple Kit project, making one change to the Glance (adding an image) and getting the error. I've logged the following error with Apple in their Bug Reporter.

Title

Receive clientIdentifier for interfaceControllerID not found when navigating to Glance

Description

I receive the following error which appears to be a false negative when navigating to a Glance in a watchOS 2.0 project. I reproduced this by creating a brand new Apple Kit project, making one change to the Glance (adding an image) and getting the error.

Steps to reproduce

  1. Clear all data in both watch and iOS simulators.
  2. In XCode, create a new WatchKit application including complication and glance.
  3. Run and see no issues.
  4. Add a png to your image assets.
  5. Add a UIImageView to the Glance in Interface Builder.
  6. Run the extension in the watch simulator.
  7. Enable the Glance in the iOS Watch companion app.
  8. Navigate to the Glance in the watch simulator.
  9. Note the follow error in your log.

2015-07-16 08:35:10.663 restaurant-reports WatchKit App Extension[78301:2211560] *********** ERROR -[SPRemoteInterface _interfaceControllerClientIDForControllerID:] clientIdentifier for interfaceControllerID:3118001E not found

Expected result

No false negatives should appear in log

Actual result

False negative appears in log

Watch OS version (build)

2.0 (13S5293f)

They gave me bug id 21853566.

I think you forgot to use the storyboardID to your class. That's what i get from your error.

I had this problem when I renamed the WatchKit target. When I renamed it back the error went away.

The better way to do a push/pop controller is running that piece of code into the main thread so:

dispatch_async(dispatch_get_main_queue(), ^{
     [self pushControllerWithName:@"controllerIdentifier" context:data];
});

dispatch_async(dispatch_get_main_queue(), ^{
     [self popToRootController];
});

dispatch_async(dispatch_get_main_queue(), ^{
     [self popController];
});

Apple documentation says about the three methods:

Always call this method from your WatchKit extension’s main thread.

I was able to fix this by removing didSet observers from my IBOutlets. tymac's troubleshooting code was helpful. It seems that the interface elements were not available yet, as didSet was getting called before awake(withContext:).

You need to verify the view controller is in your compile source here: Select Project > Select Watchkit Extension Target > Build Phases > Compile Sources

cnoon

It's not anything you're doing wrong. This is already a known issue. See my answer here. Please dupe the following radar on Apple's Bug Reporting System to help raise the priority to get this fixed.

I was having same issues after the recent 8.2 release. I had to go to each one of my InterfaceControllers and adjust its custom class module to whatever was shown as an option or "none".

I had this problem when I mistakenly set root interface controller's identifier. When I remove the identifier, this warning disappeared.

The controller’s Module name should be the same name as your Project’s root name (top left blue Xcode document icon name).

Your dynamic interface’s module name should be that same name and your destination controller’s module name (i.e. the one you're pushing to) should also be the same name.

Btw, in case you’re new or not sure I thought I’d throw this in because you might be thinking your class is wrong or something. Your Dynamic Interface Controller doesn’t have to point to the default Xcode NotificationController.swift class. Of course you can create a custom class i.e. FriendRequestNotificationController

To troubleshoot you can add this code into awakeWithContext method to see what controllers have what IDs.

override func awakeWithContext(context: AnyObject?) {
    super.awakeWithContext(context)
    if let vcID = self.valueForKey("_viewControllerID") as? NSString {
        print("Controller: \(vcID)")
    }

    // Configure interface objects here.
}
Vivek Gupta
  • If you are using page-based navigation (from where you are handling push or presenting a new view controller) then please present the new controller instead of pushing it.
  • Since first screen which if page based (like page view controller) screens, then it by default uses pushing of next page or previous page on swiping left and right and it becomes root window view of your WatchKit app. In this case if you push another controller on click from inside controls then it will not recognise the push but it will recognise present new controller. Hence please do follow the rules if possible.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!