So this all came around when subclassing
UIView. Something like below
1 2 3 4 5 6 7
and creating an instance like below
But xcode hits me with the error
‘required’: initializer ‘init(coder:)’ must be provided by subclass of ‘UIView’
After a bit of reading, it seems that effectively what I have done is override a designated initializer in UIView. You see, unlike Objective-C, Swift subclasses do not inherit their superclass initializers by default. Actually, if we read the documentation around Automatic Initializer Inheritance, we can understand why that compiler error is coming up. I’ve just quoted the two rules that apply here straight from the documentation
If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.
If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition—then it automatically inherits all of the superclass convenience initializers.
So here it seems I broke Rule 1. I haven’t inherited the
init(coder:) initializer because I have defined my own designated initializer by overriding
init. And since
UIView conforms to
init(coder:) initializer is required.
Ok, so this kinda sucks. I’ll implement
init(coder:) and just call super to satisfy the complier
1 2 3 4 5 6 7 8 9 10 11
Oh crap. When I run this, I now get
fatal error: use of unimplemented initializer ‘init(frame:)’
Hmmm. So it looks like the implementation of
init() calls out to the
init(frame:) (which I did not inherit from
UIView since I broke Rule 1). To fix this, I must implement
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Since I always want the
CustomView always to be red, then I should move that code to the other designated initializers
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Now at this point you would think I could go ahead and delete my implementation of
init(), but in fact
init() is a designated initializer inherited from NSObject. Despite the fact that
UIView’s implementation of
init(frame:), it is not a considered a convenience initializer. You can try this by deleting
init(), and you should get a compile error when trying to do
let customView = CustomView(). If it was a convenience initializer, it would have been inherited after we implemented both
UIView is implemented in Objective-C before Swift and these rules came along, it can break these rules of a designated initializer calling another designated initializer.
So basically when creating a simple subclass of UIView, it seems that if I wanted to do some setup at initialization I have to implement/override the following
just so that I can do
These rules are to ensure safety around initialization, but it sure can be confusing at first why you have to jump through those hoops just to get something simple done.