The problem with subclassing UITextView (and UICollectionView) is that designated constructor is "initWithFrame". But in real life, when it loads from storyboard, initWithCoder will be called.
class BorderedTextView: UITextView {
//will be called
init(coder: NSCoder?){
//constant values here is not an option
super.init(frame: CGRectMake(0,0,100,100), textContainer: nil)
}
//will not be called
init(frame: CGRect, textContainer: NSTextContainer!) {
super.init(frame: frame, textContainer: textContainer)
}
}
As result I cannot call any UI customisation code on init and provide any initialization value for Swift variables except defaults.
I suppose that problem can be temporary solved by extracting frame size from "coder", but I didn't found the key for it.
Any ideas better than hardcode frame values?
(From my above comments:) This looks like a Swift bug. initWithCoder:
is called when
a view (or view controller) is instantiated from a Storyboard or Nib file, and overriding
that method works in Objective-C:
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
// Initialization code
}
return self;
}
But the equivalent Swift code
class BorderedTextView: UITextView {
init(coder: NSCoder!) {
super.init(coder: coder)
}
}
fails with the error message "must call a designated initializer of the superclass 'UITextView'".
This problem occurs with all subclasses of UIView
that have a
their own designated initializer (e.g. UITextView
, UICollectionView
).
On the other hand, the problem does not occur with subclasses of UILabel
, which
does not have a designated initializer.
The Swift language is very strict about calling the super classes' designated initializer,
but there should be a way to override initWithCoder:
for all custom UIView
subclasses, so I consider this a Swift bug.
As a workaround, you can do the custom initialisation in
override func awakeFromNib() {
super.awakeFromNib()
// ...
}
Update for Swift 1.2: This apparently has been fixed. The parameter changed, it is no longer an implicitly unwrapped optional. So this compiles and works as expected (tested with Xcode 6.4):
class BorderedTextView: UITextView {
required init(coder: NSCoder) {
super.init(coder: coder)
// ...
}
}
Update for Swift 2 (Xcode 7): init(coder:)
is a failable
initializer now:
class BorderedTextView: UITextView {
required init?(coder: NSCoder) {
super.init(coder: coder)
// ...
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With