UIView init覆盖导致IBDesignable崩溃

4
我在使用XCode 7.1的界面设计器时遇到了一个非常奇怪的问题。我有一个非常简单的UIView子类,在stroyboard编辑器中渲染正常:
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
    }

}

然而,如果我只是对它添加初始化程序覆盖:
required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

它出现了错误:

  • 错误:IB Designables:无法更新自动布局状态:代理崩溃
  • 错误:IB Designables:无法呈现DashboardHeaderView的实例:代理崩溃

我非常确定,覆盖初始化器导致了这个崩溃,因为我已经重现了几次。如果只是将其注释掉,它就能正常工作。

是否有人知道发生这种情况的原因,是否有方法可以修复/解决它?


你尝试过使用不带参数的 init() 吗? - Losiowaty
据我所记,UIView根本没有定义init()。而且,如果我理解正确的话,界面构建器使用init with coder来初始化视图。 - Igor Pantović
3个回答

2

我一整天都在苦苦思考这个问题。你需要实现以下内容:

override init(frame: frame) {
    super.init(frame: frame)
}

那是IBDesignable代理用来实例化类的初始化器。所以,在我的情况下,我还有另一个初始化器。
init(frame: CGRect, maxValue: Double, minValue: Double) {
    super.init(frame: frame)

    self.maxValue = maxValue
    self.minValue = minValue
}

我的init阻塞了IBDesignable所需的init。一旦像上面那样覆盖默认的init,我就可以选择保留我的init或将其转换为便利init:

convenience init(frame: CGRect, maxValue: Double, minValue: Double) {
    self.init(frame: frame)

    self.maxValue = maxValue
    self.minValue = minValue
}

现在我可以为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...
}

1

我在另一个SO页面上找到了答案: @IBDesignable crashing agent

你需要同时重写init(frame:)init?(coder:)。如果你只重写其中一个,IB渲染将会崩溃。


0
我曾经遇到过类似的问题,发现在 prepareForInterfaceBuilder() 函数之外为 ibdesignable 视图设置掩码会导致渲染崩溃... prepareForInterfaceBuilder() 函数只有在接口构建器中调用,而不是系统调用,因此您需要在这里和 awakeFromNib() 中设置 maskView。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接