I have a xib file which I have been able to load successfully:
let xib = MyBundle.bundle.loadNibNamed("MyXib", owner: self, options: nil)!
let confirmView = xib[0] as! MyXib
This will load and appear correctly on screen.
The class is set correctly in the xib and it casts correctly when checked in code. The file owner is also set correctly.
However, if I ever drag an object from the xib file to its class (e.g. set a button reference) then the app will crash as soon as this xib is loaded.
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: [MyXib 0x7fcaf0d3eb50 setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key button.
The init is called:
required init?(coder: NSCoder) {
super.init(coder: coder)
}
Is called so I know it finishes initializing.
There are no broken outlets or anything funky. I am literally just dragging a button and creating an outlet and then running. If I delete the outlet it will work. If I add any outlet again to anything it will crash with this same issue.
Any suggestions as to what else might be the cause? I've already looked through the main causes of this.
Solution
As suggested below I removed the file owner, deleted all the outlets and used the exact loading syntax DonMag suggested.
To use your XIB that way, you want the XIB's "root view" to be set to your custom class:
You'll need to un-do and re-do your @IBOutlet
connection(s) after making that change.
Here's an example XIB (named 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>
and here is code for the class and example use in a view controller:
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
}
}