有人可以非常详细地向我解释如何正确地为UIView创建自定义初始化程序吗?

时间:2018-03-18 04:49:43

标签: swift uiview initialization optional

为UIView创建自定义子类怎么这么难?我想要做的就是能够将一个字符串传递给视图并将视图的标题设置为某些文本,但是当我尝试编译代码时,我得到错误self.inputField is not initialized at super.init call

class TextInputView: UIView {
    public var inputField:UITextField

//MARK: Lifecycle

    convenience init(withHeader header:String) {
        self.init(frame:CGRect.zero)
        self.inputField = UITextField.init(forAutoLayout: ())

        let headerLbl = UILabel.init(forAutoLayout: ())
        headerLbl.textColor = UIColor.red
        headerLbl.text = header

        headerLbl.autoPinEdge(.top, to: .top, of: self)
        headerLbl.autoPinEdge(.leading, to: .leading, of: self)


        self.inputField.adjustsFontSizeToFitWidth = true
        self.inputField.autoPinEdge(.top, to: .bottom, of: headerLbl)
        self.inputField.autoPinEdge(.leading, to: .leading, of: self)
        self.inputField.autoPinEdge(.right, to: .right, of: self)
        self.inputField.autoPinEdge(.bottom, to: .bottom, of: self, withOffset: -5)

    }

    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

为了解决这个问题,我要么必须设置inputField!还是inputField?谁能解释为什么?为什么只需设置自定义初始化程序就可以使用可选链接?

1 个答案:

答案 0 :(得分:1)

要求堆栈溢出“非常详细地解释”在The Swift Programming Language中已经详细解释的内容是不合理的。

但是,我们可以帮助您了解您编写的初始化程序有什么问题。我们来看看吧。

这是您的第一个初始化程序:

convenience init(withHeader header:String) {
    self.init(frame:CGRect.zero)
    self.inputField = UITextField.init(forAutoLayout: ())

    let headerLbl = UILabel.init(forAutoLayout: ())
    headerLbl.textColor = UIColor.red
    headerLbl.text = header

    headerLbl.autoPinEdge(.top, to: .top, of: self)
    headerLbl.autoPinEdge(.leading, to: .leading, of: self)


    self.inputField.adjustsFontSizeToFitWidth = true
    self.inputField.autoPinEdge(.top, to: .bottom, of: headerLbl)
    self.inputField.autoPinEdge(.leading, to: .leading, of: self)
    self.inputField.autoPinEdge(.right, to: .right, of: self)
    self.inputField.autoPinEdge(.bottom, to: .bottom, of: self, withOffset: -5)

}

为什么这是一个方便的初始化器?似乎TextInputView的工作是显示标题和文本字段,这是唯一这样做的初始化程序。在调用convenience之前删除super.init并初始化属性,将其设为指定的初始值设定项。此外,它似乎不会将标签和文本字段添加为子视图。也许你的autoPinEdge方法适合你吗?似乎不太可能,但我想这有可能......

无论如何,通过将其设为指定的初始值设定项,您还可以使inputField成为let而不是var

public let inputField: UITextField

init(withHeader header:String) {
    inputField = UITextField.init(forAutoLayout: ())

    super.init(frame:CGRect.zero)

    let headerLbl = UILabel.init(forAutoLayout: ())
    headerLbl.textColor = UIColor.red
    headerLbl.text = header

    addSubview(inputField)
    addSubview(headerLbl)

    headerLbl.autoPinEdge(.top, to: .top, of: self)
    headerLbl.autoPinEdge(.leading, to: .leading, of: self)

    inputField.adjustsFontSizeToFitWidth = true
    inputField.autoPinEdge(.top, to: .bottom, of: headerLbl)
    inputField.autoPinEdge(.leading, to: .leading, of: self)
    inputField.autoPinEdge(.right, to: .right, of: self)
    inputField.autoPinEdge(.bottom, to: .bottom, of: self, withOffset: -5)
}

接下来,让我们看一下您对init(frame:)

的覆盖
override init(frame: CGRect) {
    super.init(frame: frame)
}

这不能编译,因为作为指定的初始化程序,在调用super.init之前需要初始化存储的属性。但你甚至想要这个初始化器吗?它不会设置标签和文本字段。由于超类不是required,因此您可以完全删除此初始化程序。

最后,这是您的NSCodable初始化程序:

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

你必须这样做,因为UIView说它是required。这个实现是由编译器修复它生成的。如果您不打算从故事板xib加载TextInputView,则此初始化程序就像它一样。