1

我正在创建一个自定义呈现控制器,用于在呈现视图控制器时使背景变暗。演示控制器在过渡开始时添加了几个子视图,效果很好。

但是,我想在Interface Builder中设置 chrome(演示文稿“框架”),因为这样更容易布局。因此,我创建了一个用于设计 chrome 的 XIB 文件。它包括一个半透明的背景视图和左上角的 ❌ 按钮,用于关闭呈现的视图控制器。对于这些子视图,我需要在我的演示控制器不是UIViewController类)中使用插座和操作。

为了实现这一点,我在 Interface Builder 和实例化视图时的代码中将 XIB 文件的所有者设置为我的自定义演示控制器:

lazy var dimmingView = Bundle.main.loadNibNamed("PresentationChromeView", 
                                   owner: self, 
                                   options: nil)?.first 
                                   as! UIView

然后我通过CTRL+ 拖动到我的演示控制器创建了相应的出口和操作:

@IBOutlet var closeButton: UIButton!

@IBAction func closeButtonTapped(_ sender: Any) {
    presentingViewController.dismiss(animated: true, completion: nil)
}

但是,在运行时应用程序崩溃,因为 UIKit 找不到出口键,并且在删除出口时,操作方法不会被触发。所以在这两种情况下都没有建立连接。

Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<_SwiftValue 0x600000458810> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key closeButton.'

我能想到为什么这不起作用的唯一原因是不允许使用不继承自UIViewor的类创建出口和操作UIViewController

这个假设正确吗?

有没有办法用非视图(-控制器)类创建出口和动作?

4

3 回答 3

2

您可以在任何继承自NSObject. 这里的问题似乎是您没有在界面生成器中设置自定义类:

'[<NSObject 0x60800001a940> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key closeButton.'

在解码您的 Nib 时,NSCoder尝试closeButton在 的实例上设置属性,该实例NSObject当然没有此属性。您要么没有指定自定义类,要么建立了无效的连接。

于 2017-05-23T11:12:19.327 回答
0

好的...主要问题是必须实例化XIB / NIB文件,而不仅仅是加载第一项。

所有这些变化都在DimmingPresentationController.swift

// don't load it here...
//lazy var dimmingView = Bundle.main.loadNibNamed("DimmedPresentationView", owner: self, options: nil)?.first as! UIView
var dimmingView: UIView!

然后...

private func addAndSetupSubviews() {
    guard let presentedView = presentedView else {
        return
    }

    // Create a UINib object for a nib (in the main bundle)
    let nib = UINib(nibName: "DimmedPresentationView", bundle: nil)

    // Instante the objects in the UINib
    let topLevelObjects = nib.instantiate(withOwner: self, options: nil)

    // Use the top level objects directly...
    guard let v = topLevelObjects[0] as? UIView else {
        return
    }
    dimmingView = v

    // add the dimming view - to the presentedView - below any of the presentedView's subviews
    presentedView.insertSubview(dimmingView, at: 0)

    dimmingView.alpha = 0
    dimmingView.frame = presentingViewController.view.bounds

}

应该这样做。如果它对您不起作用,我可以向您的 GitHub 存储库添加一个分支(很确定我没有进行任何其他更改)。

于 2017-05-23T16:22:57.590 回答
0

导致应用程序崩溃的问题是无法推断dimmingView' 的类型(这很奇怪,因为编译器不会抱怨)。将显式类型注释添加到属性的声明中修复了崩溃。所以我简单地替换了这条线

lazy var dimmingView = Bundle.main.loadNibNamed("PresentationChromeView", 
                                   owner: self, 
                                   options: nil)?.first 
                                   as! UIView

用那一行:

lazy var dimmingView: UIView = Bundle.main.loadNibNamed("PresentationChromeView", 
                                           owner: self, 
                                           options: nil)?.first 
                                           as! UIView

出口和动作现在已正确连接。

为什么这种类型推断不起作用,或者为什么这能解决问题对我来说仍然是个谜,我仍然愿意解释。❓</p>

于 2017-05-23T17:00:10.903 回答