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



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

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

为了实现这一点,我将 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.'

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

这个假设正确吗?

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

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

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

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

好的......主要问题是必须实例化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 存储库中(很确定我没有进行任何其他更改)。

导致应用程序崩溃的问题是无法推断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

插座和操作现在已正确连接。

为什么这种类型推断不起作用,或者为什么这恰恰解决了这个问题,这对我来说仍然是一个谜,我仍然愿意解释。 🙂❓

最新更新