Does your view code look like this?
If the answer is yes then you are like me until recently when an idea crossed my mind. The idea which I find so beautiful that I need to share it with all of you.
The code in the closures represents the respective subviews’ styles. It is nothing more than that, yet it clutters the view class interface and implementation. Moreover, the same or similar code is often duplicated throughout the app codebase. How do we make it better? By doing the only logical thing — moving such code out of the view classes.
A way to do that is very simple. We will stick with the closures as in the snippet above, but with a minor change — we will not instantiate view in the closure, rather we will give the closure an instance of the view to style. We will also wrap that closure in a struct so that we can easier work with it. The struct shall be known as Style<View>
.
It is just a struct that wraps single-argument closure. There is a restriction that the argument type has to be UIView
or its subclass.
We can now style a view by passing it to the apply method. However, let us make it even simpler by defining few extensions.
Now we can do it the other way around, but also using the convenience initializer. Unfortunately, there are limitations to Swift generics because covariance is not generally supported and we want to be able to style, for example, an instance of UILabel
with an instance of Style<UIView>
. For that reason we have to cast. A small price to pay.
We now have everything needed to improve our view classes — move the code that represents style into a stylesheet type. It will just be an enum that provides us with a namespace. We can group related styles into another nested enum. This is how it can look like:
How you define stylesheet is completely up to you. It could be one stylesheet for the whole app or it could be separate stylesheets per modules. You can add styles or groups of styles using extensions and you can define reusable or private styles. It is very flexible approach, simple and, best of all, makes view classes extremely clean:
The presented solution greatly resembles how styling is done on the web — an aproach that has stood the test of time. You can easily take all this to the next level by defining few extensions on Style
type that provide inheritance and other ways of composition that will enable to you easily define global or shared styles.
I would love to hear you feedback so feel free to leave a comment if you like it or have any conerns.
The presented solution is part of the Layoutless library. Apart from declarative styling, it provides a way to make simple declarative layout.