Don’t subclass UIKit controls (e.g. UIButton
, UILabel
, UITextField
and UISlider
).
UIKit is built on composition, and this fact is reflected throughout its API. Notice how almost none of the methods on UIKit controls require subclassing. This is by design.
When you subclass a UIKit control, you’re forced to make assumptions about the internals of that control and how it behaves. These internals could change from one version of iOS to another, causing subtle issues that are difficult to reproduce.
What’s more, some UIKit controls (such as UIButton
) have initializers that are implemented as factory methods that vend private types. This means that your custom initialization code won’t even be run.
Instead of subclassing UIKit controls, opt for one of the following approaches:
Configuration
If your requirements can be achieved by styling the component using its public API, use that when you declare the variable . By assigning a default value using a closure, you can neatly organize configuration outside of your lifecycle methods.
For example, don’t do:
Instead do:
If your styles are often reused throughout your application, keep them organized in a single place and avoid code repition.
Customization
Sometimes, you need to compose multiple views together in order to achieve the desired result. If this is the case, subclass UIView
and make your changes in there. Do not attempt to modify the view hierarchy of a UIKit control.
For example, if you want your UITextField
to display an error message when validation fails on its contents, create your own subclass of UIView
that will contain both the text field and the error label. Do not attempt to add the error label directly to the UITextField
’s view hierarchy.
In the case where you need to change the behaviour of a UIKit component without adding additional views, the same advice applies: create a subclass of UIView
and implement the new behaviour in there.
For example, if you want to create a UIButton
that toggles between two states, create your own UIView
subclass to wrap the UIButton
instead of adding that behaviour to a UIButton
subclass directly.
Exceptions
There are situations where subclassing is necessary, which revolves around API that require subclassing. You may subclass UIKit controls in order to use this API, but the above guidelines still apply; configuration and customization that can be added outside of the subclassed component should remain outside.
layoutSubviews()
layoutSubviews()
is your opportunity to make changes to your view and its hierarchy after receiving a frame, but before drawing to the screen. In the rare instances where you need your code to run during the layout process, you may need to subclass a UIKit control in order to override this method.
UINavigationBar
You may need to subclass UINavigationBar
and supply the custom subclass to UINavigationController
in order to customize certain behaviours.
Drawing Text and content with UIButton, UILabel and UITextField
UIButton
, UILabel
and UITextField
have some custom drawing API that relies on subclassing. The methods are as follows: