Swift Protocols

A portrait painting style image of a pirate holding an iPhone.

by The Captain

on
May 22, 2023

Using Swift Protocols to Define Behaviors and Requirements

Swift protocols are important constructs that define a set of behaviors and requirements that a class, struct, or enum must implement. Protocols define how a type is expected to behave or the services it must provide, but not the implementation details. They allow you to write generic code and enable polymorphism, which means that you can treat objects of different classes or types as if they were the same.

Here's a simple example where we define a protocol called Identifiable that requires conforming types to have an id property that is a string:

protocol Identifiable {
    var id: String { get }
}

We can now create a struct or class that conforms to this protocol:

struct Person: Identifiable {
    var id: String
    var name: String
}

let person = Person(id: "123", name: "John")
print(person.id) // 123}

In this example, the Person struct conforms to the Identifiable protocol by providing an implementation for the id property. We can now use the person object as if it were an Identifiable object:

func displayID(item: Identifiable) {
    print("ID: \(item.id)")
}

displayID(item: person) // ID: 123}

In this function, we pass a parameter of type Identifiable, which means that we can pass any object that conforms to this protocol. The displayID function only knows about the id property and doesn't need to know the details of the object's type or implementation.

Protocols are also useful for defining event handling and delegation patterns. For example, let's define a protocol called ButtonDelegate that requires the implementation of a buttonTapped method:

protocol ButtonDelegate {
    func buttonTapped(sender: UIButton)
}

class ViewController: UIViewController {
    var delegate: ButtonDelegate?
    
    @IBAction func buttonTapped(_ sender: UIButton) {
        delegate?.buttonTapped(sender: sender)
    }
}

In this example, the ViewController class has a delegate property of type ButtonDelegate, which allows another object to handle the buttonTapped event. We can now create another class that conforms to the ButtonDelegate protocol:

class MyButtonDelegate: ButtonDelegate {
    func buttonTapped(sender: UIButton) {
        print("Button tapped")
    }
}

let myButtonDelegate = MyButtonDelegate()
let viewController = ViewController()

viewController.delegate = myButtonDelegate
viewController.buttonTapped(UIButton())}

When the button in the ViewController is tapped, the buttonTapped method is called on the MyButtonDelegate object and "Button tapped" is printed to the console.

Conclusion

Swift protocols make it easy to define a set of behaviors and requirements that conforming types must implement. They enable polymorphism and allow you to write generic code that can work with objects of different types. Protocols are also useful for defining event handling and delegation patterns.