Swift: Protocols

In Objective-C, you are allowed to define protocols which declare the methods expected to be used for a particular situation. In Swift, protocols are basically a named contract that your types should conform to. If your type says it conforms to Equatable, then it better fulfil all of the required methods to make it equatable.

Protocol

A protocol defines the body of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol doesn’t actually provide an implementation for any of these requirements, it only describes what an implementation will look like. The protocol can then be adopted by a type, struct, or enum to provide an actual implementation of those requirements. Any type that declares itself to conform to this protocol must implement the requirements dictated in the protocol. Protocols can require that conforming types have specific instance properties, instance methods, type methods, operators, and subscripts.

Syntax

You define protocols in a very similar way to types, structs, and enums:
protocol SomeProtocol {
    // protocol definition goes here
    func someFunc() // sample method
}

Implementation

The protocol name is appended beside the superclass name, separated with a comma. If there isn’t a superclass, then you just write the protocol in place of the superclass.
// protocol without superclass
class MyClass : SomeProtocol {
    // Conforming to SomeProtocol
    func someFunc() {

    }
}

// protocol with superclass
class AnotherClass : SomeSuperClass, SomeProtocol {
    // A subclass conforming to SomeProtocol
    func someFunc() {

    }
}

Declaring Requirements

A protocol can require any type that comply to provide an instance or type property with a particular name and type. The protocol doesn’t require whether the property should be a stored property or a computed property – it only specifies the required property name and type. The protocol also specifies whether each property must be gettable or gettable and settable. If a protocol requires a property to be gettable and settable, that property requirement cannot be fulfilled by a constant stored property or a read-only computed property. If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it is valid for it to be settable if this is useful for your own code. Property requirements are always declared as variable properties, prefixed with the var keyword. Gettable and settable properties are indicated by writing { get set } after their type declaration, and gettable properties are indicated by writing { get }.
protocol SomeProtocol {
    var mustBeSettable: Int { get set } // read-write
    var doesNotNeedToBe: Int { get } // read-only
}
The mustBeSettable property is { get set }, so it must be settable and thus must be a var in the type that conforms to this protocol. If you want a property like doesNotNeedToBe as immutable, you can not use let but you should rather use var and only declare a { get } specifier.

Protocols

As far as Swift is concerned, there are three protocols you can use to broaden your object’s capabilities: Equatable, Comparable, and Printable. This is referred to as Apple’s official Swift guide protocols. It is possible to guess the protocol’s function to induce a specific behaviour just by reading their name.

Equatable Protocol

Objects who comply with the Equatable protocol can be evaluated for equality and inequality, hence the name – Equal. Declaring an object as equatable provide several useful capabilities, notably the capability of making it possible to determine whether two values of the same type are considered equal. For a type to be Equatable, an implementation of the == operator must exist.
func ==(lhs: Self, rhs: Self) -> Bool
For value types, equality is determined by evaluating each property’s equality. The method returns a Bool value type, this means the method should return true if the provided values are equal, otherwise return false. As an example, consider a struct with properties name, value, and category with types String, Int, and String respectively.
struct Person {
    var name: String
    var value: Int
    var category: String
}
Since our struct is comprised of three properties, two Person are equal if, and only if, the properties’ respective values are equal.
// MARK: - Extensions
extension Person : Equatable {}
func ==(lhs: Person, rhs: Person) -> Bool {
    return lhs.name == rhs.name && lhs.value == rhs.value && lhs.category == rhs.category
}
let value1 = Person(name: "Anna", value: 6, category: "Ballet")
var value2 = Person(name: "Giesel", value: 5, category: "Contemporary")
let firstCheck = value1 == value2
// firstCheck is false

value2.name = "Anna"
let secondCheck = value1 == value2
// secondCheck is false

value2 = value1
let thirdCheck = value1 == value2
// thirdCheck = true

let fourthCheck = value1 != value2
// fourthCheck is false
An implementation of `!=` is automatically added drawing it’s implementation from the standard library.
!= is implemented as a generic function for Equatable and any type that conforms to Equatable automatically gets the != operator. If you really wanted to, you can override the implementation of != :
func !=(lhs: Person, rhs: Person) -> Bool {
    return !(lhs == rhs)
}
Operators: Equatable Protocol
Operator Description
== Determines whether the left hand value is equal with the right hand value
!= Determines whether the left hand value is not equal with the right hand value
It makes sense that two name property of the struct with same values would be equal, but two Person objects can have the same name, but be different people.

Comparable Protocol

The Comparable protocol makes it possible to compare two values of the same type. Building on Equatable, Comparable allows for more specific inequality, distinguishing cases where the left hand value is greater than the right hand value. There is one required operator overload defined in the protocol <, as well as one defined in the inherited Equatable protocol ==. By adopting the Comparable protocol and adding an operator overload for <, you automatically gain the ability to use >, <=, and >=.
func <(lhs: Self, rhs: Self) -> Bool
func <=(lhs: Self, rhs: Self) -> Bool
func >(lhs: Self, rhs: Self) -> Bool
func >=(lhs: Self, rhs: Self) -> Bool
Operators: Comparable Protocol
Operator Description
< Determines whether the left hand value is less than the right hand value
<= Determines whether the left hand value is less than or equal with the right hand value
> Determines whether the left hand value is greater than the right hand value
>= Determines whether the left hand value is greater than or equal with the right hand value
Since the Comparable protocol inherits the Equatable protocol, == is used with < and > operators to create <= and >= operators. Extending our Person type to comply with the Comparable protocol:
extension Person : Comparable {}
func <(lhs: Person, rhs: Person) -> Bool {
    return lhs.name < rhs.name && lhs.category < rhs.category
}
In this example, we excluded the value property to make the comparing more clearer by using a single property type: String
value2 = Person(name: "Giesel", value: 5, category: "Contemporary") // Let's reassign the value

let fifthCheck = value1 < value2
// fifthCheck is true

let sixthCheck = value1 > value2
// sixthCheck is false
Just like the != operator of the Equatable protocol, all other Comparable operators are automatically added after declaring the < operator. It's because of the Swift Standard Library provides a default implementation of the Comparable protocol based entirely on the existential type _Comparable. This means that all other operators can be derived from == and <, all of that functionality is made available automatically through type inference.

Printable Protocol

Printable Protocol is the third and last protocol on Apple's official Swift guide protocols.
Objective-C has a similar method `- description` that returns an `NSString`.
The Printable protocol allows you to customize the textual representation of any type ready for printing. A type must adopt this protocol if you wish to supply a value of that type to the print(_:) and println(_:) functions. Extending, again, our Person type to comply with the Printable protocol:
extension Person : Printable {
    var description: String {
        return "<\(self): Name: \(self.name), Value: \(self.value), Category: \(self.category)>"
    }
}
This protocol only consist of one variable: description; a string containing a suitable textual representation of the receiver and is read-only.
print(value2.description)
// <__lldb_expr_138.Person: Name: Giesel, Value: 5, Category: Contemporary>
This property is required for any type that adopts the Printable protocol. Use it to determine the textual representation to print when, for example, you need to display to the user their list of to dos or shopping list.
Angelo Villegas is an iOS Software Engineer from Manila. Building native iOS apps using Xcode, Objective-C and Swift, contribution to the open-source community and writing articles on AngeloVillegas.com