DESIGN PATTERNS IN IOS

UIKit and Decorator Design Pattern. Part 1. Hyperlinked UILabel.

What is a Decorator design pattern and how we can use it. Making clickable UILabel with url property.

Andrey Soloviev
4 min readAug 13, 2020
Image by Albrecht Fietz from Pixabay

Design patterns are general solutions to a commonly occurring problems, understanding them gives you more freedom and confidence of choosing solution to a specific problem.

In this series of “Design patterns for iOS”, I will go through all common design patterns and show how you could use them in your UIKit or SwiftUI applications.

I will also adhere to swift’s best practices and point them out so some of you may find something useful besides the main topic.

In this part I’ve choose to have simple example as I want to focus more on the decorator design pattern itself and how we can abuse UIView behavior to make the usage even simpler.

Next part would have a bit more difficult example but the main principle of using Decorator pattern will remain the same.

So, let’s start.

“Decorator is a structural design pattern that lets you attach new behaviors to objects by placing these objects inside special wrapper objects that contain the behaviors.” — refactoring.guru

Now when we have this definition lets implement simple decorator that takes URL property and make UILabel clickable:

As you can see the implementation is straight forward. It takes UILabel, adds UITapGestureRecognizer and on tap it opens URL. We keep URL optional so it could be changed anytime.

Notice that we defined HyperlinkDecorator as a class, not struct. That’s because it has property with reference type. In this example we don’t really need to keep reference to UILabel, but let’s leave it there.

Now if we want to use our decorator we need to create and store it somewhere. UIGestureRecognizer does not retain it’s target, so if we don’t store the reference to hyperlinkDecorator it will get deallocated straight away.

I don’t like to store references to objects that I don’t really use. If we have many decorators then we would have to create additional property for each of them and the code gets harder to read and maintain. We can also create an array or set of such objects and store them all there, so they will be deallocated together with HyperlinkViewController:

It may look better but I don’t like it either. That’s how I came to the next solution that I still use to get rid of such references by working with UIKit components.

We subclass HyperlinkDecorator from UIView, make it .zero size and add as a subview of UILabel, so it will live and die together with UILabel. We also set weak reference to UILabel to avoid retain cycle and memory leaks:

The usage remains the same but we no longer need to keep the reference:

That looks okay, but we can do it even better. Let’s make an extension for UILabel that hides this implementation and provides us convenient url property:

There is generic function subview(type:) that searches for the subview of a specific type. I could use tag but I prefer this version as the code looks cleaner and we don’t need to worry about assigning unique tag value.

And that’s how we can use it now:

Now it looks much better and I would actually stop here, but still can refactor UILabel extension and make it easier to add new properties and new decorators.

That’s what I’m going to do:

  • Move subview(type:) to the UIView extension
  • Add ViewDecorator protocol
  • Add another generic function viewDecorator(type:) to the UIView extension that would search and create new decorator if it’s not found.
  • Conforms HyperlinkDecorator to ViewDecorator protocol
  • Update UILabel extension

It seems not much changes, let’s do it.

Moving function subview(type:) to UIView:

View decorator should be subclass of UIView and should take any generic object of UIView or its subclass. Exact class of this generic object would be defined inside each view decorator.

Now let’s move code of searching and creation of new decorator from UILabel extension to separate generic function inside UIView extension:

This function works exactly the same as before only now it’s generic. If you’re unable to understand how it works, please read more about generics.

Conforming HyperlinkDecorator to ViewDecorator is simple, just add protocol conformation and replace init(label:) with init(object:)

Here’s complete code for HyperlinkDecorator:

And finally updated extension of UILabel, the reason for all of these steps:

That’s it, that’s all. You can find complete example project here.

In the next few parts I will show you few more useful extension based on this ViewDecorator that I’ve used in my projects.

--

--