【问题标题】:WatchKit: unable to find interface controller classWatchKit:找不到接口控制器类
【发布时间】:2015-05-18 02:48:48
【问题描述】:

我尝试将界面控制器添加到情节提要,将其自定义类设置为 WKInterfaceController 子类,在模拟器中启动应用程序并导航到指定的界面控制器。

当我这样做时,我收到以下错误:

WatchKit 错误 - 无法找到要实例化的接口控制器类“TestController”

如果我尝试与控制器交互(例如,尝试启动其按钮的操作),我会收到以下错误:

  • *********** 错误 -[SPRemoteInterface _interfaceControllerClientIDForControllerID:] 未找到 interfaceControllerID:(null) 的 clientIdentifier
  • *********** 错误 -[SPRemoteInterface _interfaceControllerClientIDForControllerID:] 未找到 interfaceControllerID:7120004 的客户端标识符

我尝试了setting the module name as recommended on this answer,但仍然出现以下错误:

  • WatchKit 错误 - 无法找到要实例化的接口控制器类 '_TtC29myWatchApp_WatchKit_App19TestController'
  • *********** 错误 -[SPRemoteInterface _interfaceControllerClientIDForControllerID:] 未找到 interfaceControllerID:(null) 的客户端标识符
  • *********** 错误 -[SPRemoteInterface _interfaceControllerClientIDForControllerID:] 未找到 interfaceControllerID:6E20004 的客户端标识符

【问题讨论】:

    标签: ios storyboard watchkit


    【解决方案1】:

    重命名 WatchKit 目标后出现此错误,但最终意识到:如果重命名 WatchKit 目标,则必须通过 Interface Builder 中的接口,并确保每个模块的模块名称也被重命名.

    您可以通过选择一个接口控制器、单击 Identity Inspector(或 command-option-3)、删除模块名称、然后使用 Tab 键来执行此操作。它将自动填写新的目标名称。那是为我做的!

    【讨论】:

    • 或者,勾选“从目标继承”选项。这样可以确保如果您再次更改名称,您将不必进行相同的练习(它会自动工作)。
    【解决方案2】:

    这个错误出现在我身上,因为我没有正确处理didDeactivate 消息。我停用的控制器仍在通过MMWormhole 接收消息。一旦我切断了该连接,错误就消失了。事实证明,在模拟器中,所有停用的界面控制器都在内存中徘徊,因此您必须小心确保它们不会再收到任何类型的消息。我不知道手表本身是否会发生这种情况,但我们当然应该假设是这样。

    【讨论】:

    • 如果您使用的是 MMWormhole,请确保停止监听 didDeactivate 中的消息,如下所示:self.wormhole.stopListeningForMessageWithIdentifier("identifier")。这为我消除了错误。
    • 我正在使用 MMWormhole,这是一个很好的提示,无论错误与否。我禁用了我的委托回调,但没有禁用监听块本身。
    【解决方案3】:

    我在这个问题上花了太多时间,但最终弄清楚了它是什么。 Apple Watch 基本上有两种导航模式:

    分层:

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

    基于页面:

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

    根据苹果:

    您不能将分层和基于页面的界面样式结合起来。在设计时,您必须选择最适合您的应用内容的样式并针对该样式进行设计。

    所以,问题是我混合了两者,这导致了未定义的行为,例如:

    *********** 错误 -[SPRemoteInterface _interfaceControllerClientIDForControllerID:] 未找到 interfaceControllerID:(null) 的 clientIdentifier

    希望这对其他开发者有所帮助

    编辑:

    只是一个对我有用的解决方法,当使用基于页面的导航时,您仍然可以呈现模态控制器(只是说):

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

    【讨论】:

    • Thx - 我最终重新设计了应用程序,以便我的登录视图与注销视图是同一页面,并根据状态简单地隐藏/显示元素。工作正常。
    • 谢谢,我从设计中删除了我的桌子,但仍然有“推”控制器,改为“当前”并修复了错误。
    【解决方案4】:

    这个错误似乎与这个密切相关:Unable to see custom classes in Interface Builder drop down

    当我最初尝试解决这个问题时,我不得不手动输入模块名称,因为自定义类和模块名称的下拉列表都是空的。

    检查故事板的源代码会发现一种解决方法。

    工作的接口控制器如下所示:

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

    不工作的接口控制器缺少customModule 和/或customModuleProvider 属性。

    因此,一种解决方法是通过右键单击故事板文件并选择Open As > Source Code,手动将这些缺失的属性添加到故事板文件中。

    一个长期的解决方案可能是修复故事板,以便自定义类出现在下拉列表中(请参阅linked question 了解一些潜在的修复)。

    更新:

    其他也可以使用的接口控制器使用customModule="myWatchApp_WatchKit_Extension"(注意_Extension_App 的区别)并且不需要customModuleProvider 属性。

    【讨论】:

      【解决方案5】:

      对我来说,这似乎是一个假阴性。我尝试了所有建议的解决方案,但随后通过创建一个全新的 Apple Kit 项目、对 Glance 进行更改(添加图像)并得到错误来证明这是 Apple 错误。我在 Apple 的 Bug Reporter 中记录了以下错误。

      标题

      接收未找到 interfaceControllerID 的 clientIdentifier 时 导航到 Glance

      说明

      我收到以下错误,似乎是假阴性 在 watchOS 2.0 项目中导航到 Glance 时。我转载了 这是通过创建一个全新的 Apple Kit 项目,对 Glance(添加图像)并得到错误。

      复制步骤

      1. 清除手表和 iOS 模拟器中的所有数据。
      2. 在 XCode 中,创建一个新的 WatchKit 应用程序,包括复杂功能和浏览功能。
      3. 运行并查看没有问题。
      4. 为您的图片资源添加 png。
      5. 将 UIImageView 添加到 Interface Builder 的 Glance 中。
      6. 在手表模拟器中运行扩展。
      7. 在 iOS Watch 配套应用中启用 Glance。
      8. 导航到手表模拟器中的 Glance。
      9. 请注意日志中的后续错误。

      2015-07-16 08:35:10.663 餐厅报告 WatchKit 应用程序 扩展[78301:2211560] *********** 错误-[SPRemoteInterface _interfaceControllerClientIDForControllerID:] interfaceControllerID:3118001E 的客户端标识符未找到

      预期结果

      日志中不应出现假阴性

      实际结果

      日志中出现假阴性

      观看操作系统版本(内部版本)

      2.0 (13S5293f)

      他们给了我错误 ID 21853566。

      【讨论】:

      【解决方案6】:

      我可以通过从我的 IBOutlets 中删除 didSet 观察者来解决此问题。 tymac 的故障排除代码很有帮助。界面元素似乎还不可用,因为 didSetawake(withContext:) 之前被调用。

      【讨论】:

        【解决方案7】:

        我认为您忘记在您的课程中使用 storyboardID。这就是我从你的错误中得到的。

        【讨论】:

          【解决方案8】:

          我在重命名 WatchKit 目标时遇到了这个问题。当我重命名它时,错误消失了。

          【讨论】:

            【解决方案9】:

            执行推送/弹出控制器的更好方法是将这段代码运行到主线程中:

            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 文档介绍了这三种方法:

            始终从 WatchKit 扩展的主线程调用此方法。

            【讨论】:

              【解决方案10】:

              您需要在此处验证视图控制器是否在您的编译源中:选择项目 > 选择 Watchkit 扩展目标 > 构建阶段 > 编译源

              【讨论】:

                【解决方案11】:

                这不是你做错了什么。这已经是一个已知问题。见我的回答here。请在 Apple 的 Bug Reporting System 上复制以下 radar,以帮助提高解决此问题的优先级。

                【讨论】:

                  【解决方案12】:

                  在最近的 8.2 版本发布后,我遇到了同样的问题。我必须转到我的每个 InterfaceControllers 并将其自定义类模块调整为显示为选项或“无”的任何内容。

                  【讨论】:

                    【解决方案13】:

                    当我错误地设置了根接口控制器的标识符时,我遇到了这个问题。当我删除标识符时,此警告消失了。

                    【讨论】:

                    • 对我来说正好相反。设置根接口控制器的标识符就可以了。
                    【解决方案14】:

                    控制器的模块名称应与项目的根名称相同(左上角蓝色 Xcode 文档图标名称)。

                    您的动态接口的模块名称应该是相同的名称,并且您的目标控制器的模块名称(即您要推送到的模块名称)也应该是相同的名称。

                    顺便说一句,万一你是新手或者不确定我是否认为我会把它扔进去,因为你可能认为你的课程是错误的或什么的。您的动态界面控制器不必指向默认的 Xcode NotificationController.swift 类。当然,您可以创建一个自定义类,即 FriendRequestNotificationController

                    要解决问题,您可以将此代码添加到 awakeWithContext 方法中,以查看哪些控制器具有哪些 ID。

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

                    【讨论】:

                    • 非常有用的调试代码——在我的案例中使用它来追踪修复(已发布解决方案)。
                    【解决方案15】:
                    • 如果您使用基于页面的导航(从您处理的位置 推送或展示一个新的视图控制器)然后请展示 新的控制器,而不是推动它。
                    • 如果基于页面的第一个屏幕(如页面视图控制器) 屏幕,则默认使用推送下一页或上一页 左右滑动页面,它成为根窗口视图 您的 WatchKit 应用程序。在这种情况下,如果您 push 另一个控制器 从内部控件单击然后它不会识别推送 但是 它将识别当前的新控制器。因此,请务必关注 如果可能,请遵守规则。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2015-05-21
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-07-14
                      • 2017-03-20
                      相关资源
                      最近更新 更多