为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?谁能解释为什么?为什么只需设置自定义初始化程序就可以使用可选链接?
答案 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
,则此初始化程序就像它一样。