加载的 Xib 总是在创建出口后立即崩溃
Loaded Xib Always Crashes As Soon As An Outlet Is Made
我有一个可以成功加载的 xib 文件:
let xib = MyBundle.bundle.loadNibNamed("MyXib", owner: self, options: nil)!
let confirmView = xib[0] as! MyXib
这将加载并正确显示在屏幕上。
class 在 xib 中设置正确,并且在签入代码时正确转换。文件所有者也设置正确。
但是,如果我将一个对象从 xib 文件拖到它的 class(例如设置一个按钮引用),那么应用程序将在加载此 xib 后立即崩溃。
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: [MyXib 0x7fcaf0d3eb50 setValue:forUndefinedKey:]: this
class is not key value coding-compliant for the key button.
初始化调用:
required init?(coder: NSCoder) {
super.init(coder: coder)
}
被调用所以我知道它完成了初始化。
没有坏掉的插座或任何时髦的东西。我实际上只是拖动一个按钮并创建一个插座,然后 运行。如果我删除插座,它将起作用。如果我再次将任何插座添加到任何东西,它都会因同样的问题而崩溃。
关于其他可能的原因有什么建议吗?我已经看过 main causes of this.
解决方案
按照下面的建议,我删除了文件所有者,删除了所有出口并使用 exact 加载语法 DonMag 建议。
我想你不想设置笔尖的所有者。除非情况是 self
对象与 XIB 顶级对象
相同 class
当您使用这种实例化方式时会发生什么?
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,您需要将 XIB 的 "root view" 设置为您的自定义 class:
进行更改后,您需要取消并重新建立 @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" width="320" height="93"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kuh-dy-Zhq">
<rect key="frame" x="8" y="8" width="304" height="77"/>
<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" width="122" height="37"/>
<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" width="122" height="37"/>
<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 的代码和在视图控制器中使用的示例:
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
}
}
我有一个可以成功加载的 xib 文件:
let xib = MyBundle.bundle.loadNibNamed("MyXib", owner: self, options: nil)!
let confirmView = xib[0] as! MyXib
这将加载并正确显示在屏幕上。
class 在 xib 中设置正确,并且在签入代码时正确转换。文件所有者也设置正确。
但是,如果我将一个对象从 xib 文件拖到它的 class(例如设置一个按钮引用),那么应用程序将在加载此 xib 后立即崩溃。
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: [MyXib 0x7fcaf0d3eb50 setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key button.
初始化调用:
required init?(coder: NSCoder) {
super.init(coder: coder)
}
被调用所以我知道它完成了初始化。
没有坏掉的插座或任何时髦的东西。我实际上只是拖动一个按钮并创建一个插座,然后 运行。如果我删除插座,它将起作用。如果我再次将任何插座添加到任何东西,它都会因同样的问题而崩溃。
关于其他可能的原因有什么建议吗?我已经看过 main causes of this.
解决方案
按照下面的建议,我删除了文件所有者,删除了所有出口并使用 exact 加载语法 DonMag 建议。
我想你不想设置笔尖的所有者。除非情况是 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,您需要将 XIB 的 "root view" 设置为您的自定义 class:
进行更改后,您需要取消并重新建立 @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" width="320" height="93"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kuh-dy-Zhq">
<rect key="frame" x="8" y="8" width="304" height="77"/>
<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" width="122" height="37"/>
<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" width="122" height="37"/>
<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 的代码和在视图控制器中使用的示例:
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
}
}