I have a custom class with its own .xib. I'm trying to incorporate IBInspectable to change the color of its background and subviews' backgrounds in IB.
In IB, when I leave 'Custom Class' blank, and add the User Defined Runtime Attribute 'bgColor' and then try to run the app, I get "...this class is not key value coding-compliant for the key bgColor." The app runs without crashing, but does not apply the color to the view.
When I set 'Custom Class' to "AxesView" and run, app crashes with "Thread 1: EXC_BAD_ACCESS (code=2, address)" and highlights the line "guard let view = Self.nib.instantiate..." in func setupFromNib() in NibLoadableExtension.swift
Is there some way to these things working together, or is this an either/or situation?
In View Controller:
var axesView = AxesView()
override func viewDidLoad() {
super.viewDidLoad()
axesView.frame = self.view.bounds
self.view.addSubview(axesView)
}
Full ViewController.swift
var axesView = AxesView()
override func viewDidLoad() {
super.viewDidLoad()
axesView.frame = self.view.bounds
axesView.bgColor = .clear
axesView.lineColor = .red
self.view.addSubview(axesView)
axesView.contentView.translatesAutoresizingMaskIntoConstraints = false
axesView.contentView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0).isActive = true
axesView.contentView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0).isActive = true
axesView.contentView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0).isActive = true
axesView.contentView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first! as UITouch
let p = touch.location(in: self.view)
axesView.vLine.center.x = p.x
axesView.hLine.center.y = p.y
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first! as UITouch
let p = touch.location(in: self.view)
axesView.vLine.center.x = p.x
axesView.hLine.center.y = p.y
self.view.setNeedsDisplay()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touchesMoved(touches, with: event)
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
touchesEnded(touches, with: event)
}
AxesView.swift
@IBDesignable class AxesView: UIView, NibLoadable {
@IBOutlet var contentView: UIView!
@IBOutlet weak var hLine: UIView!
@IBOutlet weak var vLine: UIView!
@IBInspectable var bgColor: UIColor = UIColor.white {
didSet {
contentView.backgroundColor = bgColor
}
}
@IBInspectable var lineColor: UIColor = UIColor.cyan {
didSet {
hLine.backgroundColor = lineColor
vLine.backgroundColor = lineColor
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupFromNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupFromNib()
}
}
NibLoadableExtension.swift
public protocol NibLoadable {
static var nibName: String { get }
}
public extension NibLoadable where Self: UIView {
static var nibName: String {
return String(describing: Self.self) // defaults to the name of the class implementing this protocol.
}
static var nib: UINib {
let bundle = Bundle(for: Self.self)
return UINib(nibName: Self.nibName, bundle: bundle)
}
func setupFromNib() {
guard let view = Self.nib.instantiate(withOwner: self, options: nil).first as? UIView else { fatalError("Error loading \(self) from nib") }
addSubview(view)
}
}


Your code works fine (for the most part).
Make sure you have set the Class on the correct object:
Change your
setupFromNib()func to:Here's how it looks added to a view controller in IB:
and here's how it looks via code:
EDIT
After discussion in comments, here is one approach to this
@IBDesignablexib with "draggable" cross-hair-lines.This uses constraints and modifies the
.constanton centerX and centerY to move the lines. I also moved yourtouches...funcs inside the custom view to keep things a bit more orderly.Complete example code follows, including the
NibLoadablecode (I renamed your control toTapAxesViewfor comparison):and here is the source for the
TapAxesView.xibfile:EDIT 2
Maybe worth trying... a custom
@IBDesignableview via code only ... noxibfile (or nib-loading) needed. Also, this usesCALayerfor the "cross-hair-lines" instead of subviews. Makes it a little "lighter weight."