As an iOS Developer, I have noticed how much time I expended working with the view layout. You may think that this is normal, and probably you’re right. However, there are small tips to follow that will save you time and allow to avoid a lot of problems, confusion or complexity.
Implementing our features based on the designs
Sooner or later, every single developer receives designs on how the app should look like. Reaching this point, sometimes developers are scared to see what marvelous ideas came from the designer’s mind. Because we know that it could make the implementation even more difficult.
Once received, we start transforming their images into a composition of UI elements with different rules and logic, trying to simplify them as max as possible. This point is crucial. A bad decision could make your app unflexible for future changes, and less resilience to new business requirements. Please, never underestimate this stage.
Let’s take as example 3 different views that belong to the Facebook iOS App.
Let’s think like a developer and start to decompose the view into smaller components. As an example, we could say:
- Your Birthdate View, composed of 2 different UILabels, aligned vertically, the one in the top with bold font and the one in the bottom with normal font. Both UILabels use the whole width and they are left aligned.
- Favorite Music View, composed by an UIImageView in the top and centered and an UILabel centered as well that use the whole width.
- Friend Request View, composed by probably 2 UILabels in the top, the first one with a single line and bold, the second one multiline. Then, above in the left an UIImageView with right padding, and finally we have another UILabel that uses the remaining width.
This could be an approach taken by someone that doesn’t know in depth the power of some UI elements. So, it implies that most probably the developer will create 3 different layouts to implement the 3 different views. It for sure will work but, as a result, it will finish having a lot of code and most probably a frustrated developer.
What are the alternatives then?
In this case, we are so lucky, the simplest solution as possible is the best one. It just needs one single view composed of a singe UILabel:
Discovering the power of the NSAttributedString
Every single UILabel contains a property called attributedText, this property expects to receive an object of NSAttributedString type.
Following the official Apple documentation, we have:
NSAttributedStringobject manages character strings and associated sets of attributes (for example, font and kerning) that apply to individual characters or ranges of characters in the string. An association of characters and their attributes is called an attributed string. The cluster’s two public classes,
NSMutableAttributedString, declare the programmatic interface for read-only attributed strings and modifiable attributed strings, respectively.
NSAttributedString is the best option to generate rich text. Is easy to customize and it allows hundred of possibilities.
Simplify the layout
The rending of views is one of the most expensive operations in iOS Development. That why is essential to reuse elements in run-time and reduce the layout complexity.
With the solution that we just took, we have a Win-Win. We are going to make use of a UITableViewCell which by nature is a reusable component and then inside we are going to have a single UILabel that fill to the parent container using AutoLayout.
Before to continue I heavily recommend you to take a look at my previous article Speed Up your iOS Development: The Modules’s Paradigm (part 1). Because from this point till the end we are to follow and use the examples previously described there.
Reuse the same layout along with multiples views
Although looks incredible, to fulfill the requirements from the original designs, taking the advantages of the NSAttributedString we just need to set 2 different values: backgroundColor and myLabel.attributedText.
In order to make easier to configure the view, let’s create a specific model that will contain all the information requested from the view layout. This is when the
Decorator start to play.
The Decorator is just like a simple
ViewModel object that is used to “Decorate the view” (please don’t confuse with the Decorator pattern).
How we pretend to reuse the same layout to create 3 different views, we are going to call to our Decorator class, CommonAttributedDecorator.
As you can notice, the CommonAttributedDecorator just return 2 values, backgroundColor, and attributedTitle. Exactly the same values that the main view layout was demanding.
Next step is to prepare the generic view layout that will use the decorator. We just need an
So far, everything looks so easy. But, wait for a moment…
Where is the complexity that views require?
The response is easy — everything is in the subclasses of the CommonAttributedDecorator. There we will override the backgroundColor, and attributedTitle methods to satisfice the designs.
Move the logic as much as you can to the Decorator
The Decorators have the ownership to contain the whole design logic as:
- Font Color/Size
- Constrain values
And they also include some business logic, like translations or elements that are presented/hidden depending on some business conditions.
Next, we have the decorator used for the Your Birthdate View, BirthdateAttributedDecorator.
The above image just shows the public exposed functions, however, as you can notice we are calling some internal functions as
lightColor. They are described in the same file as a private extension:
Here we have several properties, where we define all the business & design logic squeezing to the maximum the NSAttributedString power.
Please, take a look at the methods and you will quickly understand how NSAttributedString works.
The same applies to the Favorite Music View, using the FavoriteMusicAttributedDecorator.
And the additionals private properties:
And finally, the Friend Request View, creating the RequestFriendsAttributedDecorator:
And it owns private properties.
In general, the complexity of the Decorator depends directly on the complexity of the view. The more different colors, font size, and styles it has, the more programmatically code it will require.
We are going to implement a new Module with a single reusable
AttributedCell. Here we are the AttributedModule.
As you can notice, we are customizing the
AttributedCell view passing by parameter the Decorator to use:
Easy right? with just a single method, we are setting up what view is going presented.
Finally, this is how the 3 different rows look like
It could sound strange, but the use of Decorators just contains advantages:
- Makes mainly your views less complex
- Makes the views more generics and reusable
- Reduces the number of subviews
- Increases the performance
- Group the design logic in the same kind of objects.
- Saves lines of code
- Makes possible to do unit testing the content of your views
Summing up, we can say that it increases the quality, flexibility, reliability, and testability of your code.
If you want to have the same examples that we have been using here, or even more elaborated examples — I have an additional repository. It contains several Modules, and few of them look like some components used in WhatsApp and Facebook apps. Just download it, and click on the play button, you will not regret:
Example App that is implemented following the Modules Paradigm - fjtrujy/module-examples
If you try the Decorators, I’d love to hear about it. Or, hey, if you think this doesn’t make sense let me know it as well. Comments are very welcome, don’t be shy!
As you might notice, this is the second part of “Speed up your iOS Development” series (here you have the first one). Soon I will create a third part, where I will explode to the limits the Snapshot testing. Stay tuned!