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 chosen to have a 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.
The next part would have a bit more difficult example but the main principle of using Decorator pattern will remain the same. Now when we have this definition lets implement a simple decorator that takes URL property and make UILabel clickable:
As you can see the implementation is straightforward. It takes UILabel, adds UITapGestureRecognizer, and on tap, it opens the URL. We keep the URL optional so it could be changed anytime. Notice that we defined HyperlinkDecorator as a class, not a struct. That’s because it has a property with a reference type. In this example, we don’t really need to keep a 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 its 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 an 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 it as a subview of UILabel, so it will live and die together with UILabel. We also set a 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 the 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 a new decorator if it’s not found.
- Conforms HyperlinkDecorator to ViewDecorator protocol
- Update UILabel extension
It seems not many 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.
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.
Here’s the complete code for HyperlinkDecorator
About the Authors
Sign up today & start getting tech news.
Get the latest tech trends directly in your inbox each month. And get invited to exclusive events.