是否可以在非视图类中创建IBOutlet?

时间:2017-05-23 10:36:16

标签: ios uiview ibaction iboutlet uipresentationcontroller

我创建了一个自定义演示控制器,用于在显示视图控制器时调暗背景。演示控制器在转换开始时添加了几个子视图,效果很好。

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

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

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.'

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

这个假设是否正确?

有没有办法用非视图(-controller)类创建出口和操作?

3 个答案:

答案 0 :(得分:2)

您可以在继承自NSObject的任何类中创建IBOutlet。这里的问题似乎是您没有在界面构建器中设置自定义类:

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

解码你的笔尖时,NSCoder尝试在closeButton的实例上设置NSObject属性,当然这个属性没有这个属性。您未指定自定义类或无效连接。

答案 1 :(得分: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回购中添加一个分支(很确定我没有做任何其他更改)。

答案 2 :(得分: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

出口和行动现已正确连接。

为什么这种类型的推理没有用,或者为什么这个问题解决了这个问题对我来说仍然是一个谜,我仍然可以解释。 ❓