Reputation: 9246
I have a very strange problem with XCode 7.1 interface builder. I have a really simple UIView subclass, which renders fine in storyboard editor:
import UIKit
@IBDesignable
class DashboardHeaderView: UIView {
@IBInspectable
var maskClipHeight: CGFloat = 40.0
override func layoutSubviews() {
super.layoutSubviews()
self.setMask()
}
private func setMask() {
let mask = CAShapeLayer()
mask.path = self.createMaskPath()
self.layer.mask = mask
}
private func createMaskPath() -> CGPath {
let maskPath = UIBezierPath()
maskPath.moveToPoint(CGPoint(x: bounds.minX, y: bounds.minY))
maskPath.addLineToPoint(CGPoint(x: bounds.maxX, y: bounds.minY))
maskPath.addLineToPoint(CGPoint(x: bounds.maxX, y: bounds.maxY - self.maskClipHeight))
maskPath.addLineToPoint(CGPoint(x: bounds.minX, y: bounds.maxY))
maskPath.closePath()
return maskPath.CGPath
}
}
However, if I only add initializer override to it:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
It fails with errors:
I am 100% certain that that initializer override makes it crash as I've reproduced it a couple of times. If I only comment it out, it works again.
Anyone has any idea why this is happening and if there is a way to fix/workaround it?
Upvotes: 4
Views: 1643
Reputation: 454
I've been struggling with this all day. You need to implement:
override init(frame: frame) {
super.init(frame: frame)
}
That's the initializer the IBDesignable agent uses to instantiate the class. So, in my case I had another initializer as well.
init(frame: CGRect, maxValue: Double, minValue: Double) {
super.init(frame: frame)
self.maxValue = maxValue
self.minValue = minValue
}
My init was blocking the init that IBDesignable needs. Once I overrode the default init as above I had the choice of leaving my init as is or converting it to a convenience init:
convenience init(frame: CGRect, maxValue: Double, minValue: Double) {
self.init(frame: frame)
self.maxValue = maxValue
self.minValue = minValue
}
Now I can add some default behavior for IBDesigner:
var initForIB = false
init(frame: CGRect, maxValue: Double, minValue: Double) {
super.init(frame: frame)
self.maxValue = maxValue
self.minValue = minValue
initForIB = false
}
override init(frame: CGRect) {
super.init(frame: frame)
initForIB = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func drawRect(rect: CGRect) {
if initForIB {
initIBDefaults()
}
// ...do some other stuff...
}
Upvotes: 2
Reputation: 151
I've found the answer on another SO page: @IBDesignable crashing agent
You need to override both init(frame:)
and init?(coder:)
. If you override only one of the two, IB rendering will crash.
Upvotes: 1
Reputation: 1235
I've had a similar problem and found that setting a mask for ibdesignable views outside of prepareForInterfaceBuilder() function cause a rendering crash... prepareForInterfaceBuilder() is not called from the system, only by interfaceBuilder, so you will need to set the maskView here and in awakeFromNib().
Upvotes: 0