Holy Swift

Holy Swift

Chain of Responsibility Pattern in Swift

Chain of Responsibility Pattern in Swift

Big chains, no problem.

Subscribe to my newsletter and never miss my upcoming articles

Hoi mensen, Leo hier.

Today we will explore the responder chain design pattern that is responsible for for all the touches going to the right views in iOS. When a user touches the screen it starts hit test, in iOS is the responder chain patter, to check what view is under the user finger. For example: If your view hierarchy is ViewController -> UIView -> UITableView -> UITableViewCell , when the user touch the UITableViewCell if it does implement touchesBegan the action will be performed on it, otherwise it will go to the UITableView asking if it can respond to the touchesBegan and if not it will check UIView and so on.

The magic behind it all is that you don't need to actively create the responder chain with your views, the UIKit framework will do that for you! It means that every time you add a subview or a child view controller, it automatically join the chain.

Today you will create your very first Responder Chain and check how it can be simple and powerful. It's not the scope of this article to explain the Chain of Responsibility patter, others already done it in a better way that I could, we will implement it in Swift.

Let's code... but art first!

The Painting

This painting is "Young mother with child" (1520-1529), it's a masterpiece from Lucas Cranach the Elder. He was a German Renaissance painter and printmaker in woodcut and engraving. He was court painter to the Electors of Saxony for most of his career.

He was a close friend of Martin Luther. Cranach also painted religious subjects, first in the Catholic tradition, and later trying to find new ways of conveying Lutheran religious concerns in art. He continued throughout his career to paint nude subjects drawn from mythology and religion.

The reason I choose the painting is because it has a lot of chains... Got it?

The Problem

You are asked to create a a structure capable of respond to messages, but only the right receiver should respond to the input. For example: You have an authentication and authorisation system, you could just create a chain of everything you need to check and after all checks return to the caller true or false.

The first thing to do is to create the protocol. What it will look like? Well... there's some alternatives but all of them includes at least two things: you need an optional reference to the next one in the chain and need the function that will handle with the request.

The reference in the protocol must be an optional because the root of the chain will have a nil parent. Do you still think that algorithms and data structure are just for college? What this pattern looks like?

The first version I'll present here will work with three properties. I've added the action itself so we can filter what action we want.

First create the enum of actions and the protocol in playgrounds:

enum ChainAction {
    case message
    case print
    case none
}

protocol Chainable {
    var parent: Chainable? { get set }
    func handle(on id: ChainAction, message: String)
}

With that set you can implement the protocol, lets imagine that you will create some responder to the ChainAction.message , you could do like this:

struct MessageChain: Chainable {

    var parent: Chainable?
    private let chainAction = ChainAction.message

    func handle(on id: ChainAction, message: String) {
        if id == chainAction {
            print("Handling [\(message)]","was handled at action {\(chainAction)}")
        } else {
            print("This chain type [\(chainAction)] can't handle: [\(id)] type")
            parent?.handle(on: id, message: message)
        }
    }
}

This would't be useful if we didn't had any more implementations. So let's do it:

struct DefaultChain: Chainable {

    private let chainAction = ChainAction.none
    var parent: Chainable?

    func handle(on id: ChainAction, message: String) {
        if id == chainAction {
            print("Handling [\(message)]","was handled at action {\(chainAction)}")
        } else {
            print("This chain type [\(chainAction)] can't handle: [\(id)] type")
            parent?.handle(on: id, message: message)
        }
    }
}

This can be as complex as you want. You could handle all the ChainActions, or just one as the example above. Or you could even execute some task and still pass the message to others in the chain, in this case would something like the authorisation and authentication system that I mentioned above. Use your creativity.

And to test all the code you just need to create the object with the right parents and call the handle in the leaf ( the last one of the chain...) :

let c1 = DefaultChain(parent: nil)
let c2 = MessageChain(parent: c1)
let c3 = DefaultChain(parent: c2)

c3.handle(on: .message, message: "NEW MESSAGE")

This will result in:

Screenshot 2021-08-12 at 08.57.36.png

A more Objective-C way

You can also use #selectors to perform the action that you want. This way you leave to the old and good objetive-c to handle the actions. This example is heavily inspired in the book Swift Design Patterns. Let's try it out:

class Handler: NSObject, Handling {

    var next: Handler?

    init(next: Handler?) {
        self.next = next
    }

    func handle(selector: Selector) {
        if responds(to: selector) {
            perform(selector)
        } else {
            next?.handle(selector: selector)
        }
    }
}

class MessageHandler: Handler {
    @objc func handleChain() {
        print("Mission finished! We landed")
    }
}

let root = MessageHandler(next: nil)
let first = Handler(next: root)
let second = Handler(next: first)
let third = Handler(next: second)

let action = #selector(MessageHandler.handleChain)
third.handle(selector: action)

This should result:

Screenshot 2021-08-12 at 09.02.17.png

And that's it!

Summary

Today we implement the chain of responsibility pattern in Swift in two ways. The first one a Switfier version and the second one a more objective-c version. Both have the same principles and functionalities, you can pick whatever you find it best OR could create a even better one! If you create your own please share in the comments sections.

That's all my people, I hope you liked as I enjoyed write this article. If you want to support this blog you can Buy Me a Coffee or just leave a comment saying hello. You can also sponsor posts and I'm open to writing freelancing! Just reach me in LinkedIn or Twitter for details.

Thanks for the reading and... That's all folks.

credits:
image

Interested in reading more such articles from Leonardo Maia Pugliese?

Support the author by donating an amount of your choice.

 
Share this