iOS : Design Patterns

Chetan Aggarwal
9 min readFeb 28, 2018

--

“A design that doesn’t take change into account risks major redesign in the future.”
Erich Gamma

Design patterns are reusable solutions to common problems in software design. They’re templates designed to help you write code that’s easy to understand and reuse. Most common Cocoa design patterns:

  • Creational: Singleton.
  • Structural: Decorator, Adapter & Facade.
  • Behavioral: Observer and Memento

Lets get started….🏄🏻🏄🏻🏄🏻

Facade

The Facade design pattern provides a single interface to a complex subsystem. Instead of exposing the user to a set of classes and their APIs, you only expose one simple unified API.

Souce: Facade-Raywenderlich

This pattern is ideal when working with a large number of classes, particularly when they are complicated to use or difficult to understand.This is also useful if the classes under the facade are likely to change, as the facade class can retain the same API while things change behind the scenes.For example, if the day comes when you want to replace your backend service, you won’t have to change the code that uses your API, just the code inside your Facade.

Decorator

The Decorator pattern dynamically adds behaviors and responsibilities to an object without modifying its code. It’s an alternative to subclassing where you modify a class’s behavior by wrapping it with another object.

In Objective-C there are two very common implementations of this pattern: Category and Delegation. In Swift there are also two very common implementations of this pattern: Extensions and Delegation.

Delegate: This is used to keep implementation specific behavior out of the generic class. Many UI elements in iOS use delegates to control their behaviour e.g. UIScrollView. The UIScrollView class has no knowledge of what it should be scrolling as that is an application specific task. So to notify the application of scrolling events, it uses the UIScrollViewDelegate. The application can implement the delegate and then intercept the scrolling events sent to it by the UIScrollView.

Memento

In Memento Pattern saves your stuff somewhere. Later on, this externalized state can be restored without violating encapsulation; that is, private data remains private. Implementations example of the Memento pattern is Archiving, Serialization and State Restoration.

Adapter

The Adapter design pattern converts the interface of a class into another interface that clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces. It decouples the client from the class of the targeted object. Apple uses protocols to do the job. You may be familiar with protocols like UITableViewDelegate, UIScrollViewDelegate, NSCoding and NSCopying. As an example, with the NSCopying protocol, any class can provide a standard copy method.

Observer

The Observer design pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. The Observer pattern is essentially a publish-and-subscribe model in which the subject and its observers are loosely coupled. Communication can take place between the observing and observed objects without either needing to know much about the other. Cocoa implements the observer pattern in two ways: Notifications and Key-Value Observing (KVO).

Strategy

Strategy pattern allows you to change the behaviour of an algorithm at run time. Using interfaces, we are able to define a family of algorithms, encapsulate each one, and make them interchangeable, allowing us to select which algorithm to execute at run time. For more information check these two out by Thomas Hanning and Sam Stone.

Factory

Factory method pattern makes the codebase more flexible to add or remove new types. To add a new type, we just need a new class for the type and a new factory to produce it like the following code. For more information check this out.

Command

The Command design pattern encapsulates a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations. The request object binds together one or more actions on a specific receiver. The Command pattern separates an object making a request from the objects that receive and execute that request. E.g. Target action mechanism.

Composite

The Composite design pattern composes related objects into tree structures to represent part-whole hierarchies. It lets clients treat individual objects and compositions of objects uniformly. It is part of the Model-View-Controller aggregate pattern. E.g. View Hierarchy.

Iterator

The Iterator design pattern provides a way to access the elements of an aggregate object (that is, a collection) sequentially without exposing its underlying representation. The Iterator pattern transfers the responsibility for accessing and traversing the elements of a collection from the collection itself to an iterator object. The Iterator defines an interface for accessing collection elements and keeps track of the current element. Different iterators can carry out different traversal policies. E.g. Enumerators

Mediator

The Mediator design pattern defines an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently. These objects can thus remain more reusable. A “mediator object” in this pattern centralizes complex communication and control logic between objects in a system. These objects tell the mediator object when their state changes and, in turn, respond to requests from the mediator object. E.g. Controller Classes in the AppKit Framework & View Controllers in UIKit

Singleton

The Singleton design pattern ensures a class only has one instance, and provides a global point of access to it. The class keeps track of its sole instance and ensures that no other instance can be created. Singleton classes are appropriate for situations where it makes sense for a single object to provide access to a global resource. It usually uses lazy loading to create the single instance when it’s needed the first time.

Singleton, Facade and Decorator — Raywenderlich tutorials.

Adaptor, Observer and Momento — Raywenderlich tutorials

MVC

  • Models — responsible for the domain data or a data access layer which manipulates the data, think of ‘Person’ or ‘PersonDataProvider’ classes.
  • Views — responsible for the presentation layer (GUI), for iOS environment think of everything starting with ‘UI’ prefix.
  • Controller/Presenter/ViewModel — the glue or the mediator between the Model and the View, in general responsible for altering the Model by reacting to the user’s actions performed on the View and updating the View with changes from the Model.

The ViewController contains the View and owns the Model. The problem is that we used to write the controller code as well as the view code in the ViewController. It makes the ViewController too complex. That’s why we called it a Massive View Controller. While writing a test for the ViewController, you need to mock the view and the life cycle of it. But views are difficult to be mocked. And we actually don’t want to mock the view if we only want to test the controller logic. All these things make writing tests so complicated.

iOS/MacOS development — MVC

MVP

Model View Presenter has three components: the Presenter (UIKit independent mediator), the Passive View (UIView and/or UIViewController) and the Model. This pattern defines Views as recipients of the UI events, which then call the appropriate Presenter as needed. The Presenter is, in fact, responsible for updating the View with the new data returned by the Model. View is more loosely coupled to the model. The Presenter is responsible for binding the Model to the View. Easier to unit test because interaction with the view is through an interface. Usually View to Presenter = map one-to-one. Complex views may have multi presenters.

MVVM

In MVVM, the View consists of only visual elements like layout, animation, initializing UI components, etc. There’s a special layer between the View and the Model called the ViewModel. The ViewModel is a canonical representation of the View. That is, the ViewModel provides a set of interfaces, each of which represents a UI component in the View. We use a technique called “binding” to connection UI components to ViewModel interfaces.

Specifically, for MVVM in iOS development, the UIView/UIViewController represent the View. We only do:

  1. Initiate/Layout/Present UI components.
  2. Bind UI components with the ViewModel.

On the other hand, in the ViewModel, we do:

  1. Write controller logics such as pagination, error handling, etc.
  2. Write presentational logic, provide interfaces to the View.

In Swift, there are various ways to achieve the “binding”: KVO (Key-Value Observing) pattern, 3rd party libraries for FRP (Functional Reactive Programming) such as RxSwift and ReactiveCocoa and by crafting it yourself.

Check this awesome article, it covers everything about MVVM. 👌🏼

And again back to our feature assessment:

  • Distribution — it is not clear in our tiny example, but, in fact, the MVVM’s View has more responsibilities than the MVP’s View. Because the first one updates it’s state from the View Model by setting up bindings, when the second one just forwards all events to the Presenter and doesn’t update itself.
  • Testability — the View Model knows nothing about the View, this allows us to test it easily. The View might be also tested, but since it is UIKit dependant you might want to skip it.
  • Easy of use — its has the same amount of code as the MVP in our example, but in the real app where you’d have to forward all events from the Viewto the Presenter and to update the View manually, MVVM would be much skinnier if you used bindings.

The MVVM is very attractive, since it combines benefits of the aforementioned approaches, and, in addition, it doesn’t require extra code for the View updates due to the bindings on the View side. Nevertheless, testability is still on a good level.

VIPER

Problems with MVVM:

  1. It is complicated on iOS by a lack of bindings and by a tendency to continue putting too many responsibilities that were in a bloated view controller class into a bloated view model class instead
  2. Without being broken down into good, reusable, testable, and single-responsibility components, any MVVM implementation is of limited usefulness
  3. Simply saying that “we’re using MVVM” or simply having a rough implementation of MVVM in a project, without taking a thorough look at how it’s improving your code reuse, efficiency and adherence to the single responsibility principle will mislead you as to how valuable or maintainable the architecture really is.

VIPER is an application of Clean Architecture to iOS apps. The word VIPER is a backronym for View, Interactor, Presenter, Entity, and Routing. Clean Architecture divides an app’s logical structure into distinct layers of responsibility. This makes it easier to isolate dependencies (e.g. your database) and to test the interactions at the boundaries between layers.

The main parts of VIPER are:

  • View: displays what it is told to by the Presenter and relays user input back to the Presenter.
  • Interactor: contains the business logic as specified by a use case.
  • Presenter: contains view logic for preparing content for display (as received from the Interactor) and for reacting to user inputs (by requesting new data from the Interactor).
  • Entity: contains basic model objects used by the Interactor.
  • Routing: contains navigation logic for describing which screens are shown in which order.

Check below article for more detail.

Thanks for reading! 👍🏻 Please share your feedback, queries regarding any of the topic in comments below. Till then sayonara !!! ✌🏻✌🏻✌🏻

--

--