已加载的 Xib 总是在制作插座后立即崩溃

Posted

技术标签:

【中文标题】已加载的 Xib 总是在制作插座后立即崩溃【英文标题】:Loaded Xib Always Crashes As Soon As An Outlet Is Made 【发布时间】:2020-06-09 16:36:50 【问题描述】:

我有一个可以成功加载的 xib 文件:

    let xib = MyBundle.bundle.loadNibNamed("MyXib", owner: self, options: nil)!
    let confirmView = xib[0] as! MyXib

这将加载并正确显示在屏幕上。

该类在 xib 中设置正确,并且在签入代码时可以正确转换。文件所有者也设置正确。

但是,如果我将一个对象从 xib 文件拖到它的类中(例如,设置一个按钮引用),那么一旦加载了这个 xib,应用程序就会崩溃。

*** 由于未捕获的异常“NSUnknownKeyException”而终止应用程序,原因:[MyXib 0x7fcaf0d3eb50 setValue:forUndefinedKey:]: this 类与键按钮的键值编码不兼容。

init 被调用:

required init?(coder: NSCoder) 
    super.init(coder: coder)

被调用,所以我知道它完成了初始化。

没有损坏的插座或任何时髦的东西。我实际上只是拖动一个按钮并创建一个插座然后运行。如果我删除插座,它将起作用。如果我再次将任何插座添加到任何内容,它将因同样的问题而崩溃。

关于其他可能的原因有什么建议吗?我已经浏览过main causes of this。

解决方案

如下所示,我删除了文件所有者,删除了所有出口并使用 exact 加载语法 DonMag 建议。

【问题讨论】:

啊,是的,沉默的反对票。如果您要投反对票,至少解释一下您的问题。 错误信息看起来有点奇怪。当我有这个时,我相信它已经告诉我它在 [ setValue:forUndefinedKey:] 部分中抱怨哪个类。 是的,很抱歉标签弄乱了格式。它确实在错误中引用了我的类 而 MyXib 类确实有一个名为“按钮”的插座......奇怪。 该文件也已链接,因为如果我转到文件所有者,然后单击 -> 箭头,它将带我进入课堂。如果我添加一个插座,它会显示为一个实心点。我还打开了文件文本并清除了所有内容,加载了它,然后添加了一个基本的插座引用,一旦加载它就会再次崩溃 【参考方案1】:

要以这种方式使用您的 XIB,您希望将 XIB 的 “根视图” 设置为您的自定义类:

在进行更改后,您需要撤消并重新建立您的 @IBOutlet 连接。

这是一个示例 XIB(名为 BasicXIBView.xib):

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16096" targetRuntime="ios.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina3_5" orientation="portrait" appearance="light"/>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="BasicXIBView" customModule="PassBackNavController" customModuleProvider="target">
            <rect key="frame" x="0.0" y="0.0"  />
            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
            <subviews>
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kuh-dy-Zhq">
                    <rect key="frame" x="8" y="8"  />
                    <subviews>
                        <button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8KY-Pe-K0s">
                            <rect key="frame" x="162" y="20"  />
                            <color key="backgroundColor" red="1" green="0.14913141730000001" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                            <state key="normal" title="Cancel"/>
                            <connections>
                                <action selector="cancelTapped:" destination="iN0-l3-epB" eventType="touchUpInside" id="w6M-G8-kcb"/>
                            </connections>
                        </button>
                        <button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ny7-lN-ZrV">
                            <rect key="frame" x="20" y="20"  />
                            <color key="backgroundColor" red="1" green="0.14913141730000001" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                            <state key="normal" title="Continue"/>
                            <connections>
                                <action selector="continueTapped:" destination="iN0-l3-epB" eventType="touchUpInside" id="32u-xJ-uxC"/>
                            </connections>
                        </button>
                    </subviews>
                    <color key="backgroundColor" red="0.46202266219999999" green="0.83828371759999998" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                    <constraints>
                        <constraint firstItem="ny7-lN-ZrV" firstAttribute="leading" secondItem="kuh-dy-Zhq" secondAttribute="leading" constant="20" id="2rf-kC-UJW"/>
                        <constraint firstItem="ny7-lN-ZrV" firstAttribute="width" secondItem="8KY-Pe-K0s" secondAttribute="width" id="4wL-HV-gXu"/>
                        <constraint firstItem="8KY-Pe-K0s" firstAttribute="leading" secondItem="ny7-lN-ZrV" secondAttribute="trailing" constant="20" id="DM1-NU-W8P"/>
                        <constraint firstAttribute="trailing" secondItem="8KY-Pe-K0s" secondAttribute="trailing" constant="20" id="cyP-o4-Bac"/>
                        <constraint firstAttribute="bottom" secondItem="ny7-lN-ZrV" secondAttribute="bottom" constant="20" id="iaW-ir-x5w"/>
                        <constraint firstAttribute="bottom" secondItem="8KY-Pe-K0s" secondAttribute="bottom" constant="20" id="m9V-Vf-AAA"/>
                        <constraint firstItem="8KY-Pe-K0s" firstAttribute="top" secondItem="kuh-dy-Zhq" secondAttribute="top" constant="20" id="q8j-Ce-ubu"/>
                        <constraint firstItem="ny7-lN-ZrV" firstAttribute="top" secondItem="kuh-dy-Zhq" secondAttribute="top" constant="20" id="rBK-uY-4NU"/>
                    </constraints>
                </view>
            </subviews>
            <color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
            <constraints>
                <constraint firstItem="kuh-dy-Zhq" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="8" id="0ST-Ya-cGb"/>
                <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="kuh-dy-Zhq" secondAttribute="trailing" constant="8" id="3zW-8F-7Ae"/>
                <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="kuh-dy-Zhq" secondAttribute="bottom" constant="8" id="7GJ-Vc-C2u"/>
                <constraint firstItem="kuh-dy-Zhq" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="8" id="peG-dz-caP"/>
            </constraints>
            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
            <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
            <connections>
                <outlet property="backgroundView" destination="kuh-dy-Zhq" id="GTo-Hw-kwM"/>
            </connections>
            <point key="canvasLocation" x="138.75" y="-89.375"/>
        </view>
    </objects>
</document>

下面是视图控制器中的类和示例代码:

class BasicXIBView: UIView 

    @IBOutlet var backgroundView: UIView!

    @IBAction func continueTapped(_ sender: Any) 
        print("Continue Button Tapped!")
    

    @IBAction func cancelTapped(_ sender: Any) 
        print("Cancel Button Tapped!")
    



class TestXIBViewController: UIViewController 

    var confirmView: BasicXIBView!

    override func viewDidLoad() 
        super.viewDidLoad()

        let xib = Bundle.main.loadNibNamed("BasicXIBView", owner: self, options: nil)!

        // make sure it loads correctly
        guard let v = xib[0] as? BasicXIBView else 
            fatalError("XIB setup incorrectly!")
        

        // use it as our class's confirmView
        confirmView = v

        // add it
        view.addSubview(confirmView)

        // use auto-layout
        confirmView.translatesAutoresizingMaskIntoConstraints = false

        // respect safe-area
        let g = view.safeAreaLayoutGuide

        // constrain it centered X and Y,
        //  80% of the width
        //  use its internal constraints to determine its height
        NSLayoutConstraint.activate([
            confirmView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
            confirmView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            confirmView.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.8),
        ])

        // demo that we have access to backgroundView in the XIB
        confirmView.backgroundView.backgroundColor = .green

    


【讨论】:

我将文件所有者和***视图都设置为类。我从来没有尝试过将***视图设置为类并将文件所有者留空 只要我引用按钮,它就会再次崩溃:/ 之前设置的 outlet 删除了吗?你试过我的例子吗? 我做了,但我会再次尝试从头开始创建它 嗯,我不确定为什么它会突然起作用,但是当我将加载语法更改为您的建议时,它已经开始起作用了。我之前的加载代码:func loadViewFromNib() -> U_MakePaymentConfirmation! let bundle = Bundle(for: type(of: self)) let nib = UINib(nibName: "MakePaymentConfirmation", bundle: bundle) return nib.instantiate(withOwner: self, options: nil).first as! U_MakePaymentConfirmation 没用。你知道有什么区别吗?【参考方案2】:

我认为您不想设置笔尖的所有者。除非是self对象和XIB顶层对象是同一个类

当您使用这种实例化风格时会发生什么?

let nib = NSNib(nibNamed: "MyXib", bundle: nil)
var array: NSArray?
if let nib = nib 
  let result = nib.instantiate(withOwner: nil, topLevelObjects: &array)
  if result, let array = array  //first object is nominally the one you want 

或使用你的风格:

let xib = MyBundle.bundle.loadNibNamed("MyXib", owner: nil, options: nil)!
let confirmView = xib[0] as! MyXib

【讨论】:

让我看看试试。我有一个视图控制器调用这个 xib,我尝试将视图控制器作为所有者传递。我会按照您的建议尝试使用 nil 所有者 同样的问题。我还在上面添加了一个屏幕截图,显示了正在设置的后台插座。当我尝试这个时,我仍然收到错误:*** 由于未捕获的异常 'NSUnknownKeyException' 导致应用程序终止,原因:'[ setValue:forUndefinedKey:]:此类不符合键值编码的键背景.' 虽然在这种情况下说它是一个有趣的 NSObject,就像之前它会说类名 在 XIB 中,文件所有者占位符是否设置为 MyXib 或您的班级? 是的,我还添加了一个屏幕截图。另请注意,单击 -> 会将我带到课堂,因此我知道它已连接

以上是关于已加载的 Xib 总是在制作插座后立即崩溃的主要内容,如果未能解决你的问题,请参考以下文章

无法链接到 XCode9 中的插座集合

当 UICollectionViewCell 在 xib 中时连接插座出现问题

何时设置 XIB 插座属性?

无需打开插座即可连接蓝牙设备

View Controller 更新后继续加载xib文件

界面生成器中的死插座/操作错误