Advertisement

Protocols

  • Waqar Malik

Abstract

In the real world, people on official business are often required to follow strict procedures when dealing with certain situations. Law enforcement officials, for example, are required to “follow protocol” when making inquiries or collecting evidence.

Keywords

Failable Initializer Protocol Type Require Modifier Protocol Requirement Curly Brace 
These keywords were added by machine and not by the authors. This process is experimental and the keywords may be updated as the learning algorithm improves.

In the real world, people on official business are often required to follow strict procedures when dealing with certain situations. Law enforcement officials, for example, are required to “follow protocol” when making inquiries or collecting evidence.

In the world of object-oriented programming, it’s important to be able to define a set of behaviors that’s expected of an object in a given situation. As an example, a table view expects to be able to communicate with a data source object in order to find out what it’s required to display. This means the data source must be able to respond to the specific messages the table view might send.

Protocols define the interface—a blueprint of methods, properties, and other requirements for a specific task. The protocol does not actually implement the functionality itself, it only describes the implementation.

Any object that implements the requirements a protocol describes is said to conform to the protocol. A protocol can require a specific instance of the type to have:
  • Properties

  • Instance methods

  • Type methods

  • Operators

  • Subscripts

Syntax

You define a protocol in the same way you define classes, structures, and enumeration types:

protocol SomeProtocol {

    // Your protocol requirements

}

Your protocol can also inherit from another protocol:

protocol SomeProtocol : NSObjectProtocol {

    // Your protocol requirements

}

In Objective-C you could have a protocol and class with the same name, such as class NSObject and protocol NSObject, but in Swift the names can’t be the same. In the preceding example, the protocol inherits from NSObjectProtocol, which is the same as NSObject protocol in Objective-C.

When a type conforms to one or more protocols, you define that type by giving the list of protocols after the colon separator, and you can list multiple protocols using the comma separator:

struct SomeStruct : SomeProtocol, AnotherProtocol {

        // your implementation of structure

}

If your class has a parent class, you can list the protocols after the parent class:

class SomeClass : ParentClass, SomeProtocol, AnotherProtocol {

        // your implementation of class

}

Properties

Protocols can require the implementing type (or conforming type) to provide a property that can be either gettable (read-only) or settable and gettable (read-write). The protocol doesn’t specify that the specific property has to be stored or computed; the implementing type can implement the property as it likes as long as it conforms to the protocol interface.

If the property is settable, it can’t be either a constant stored or gettable computed property. Only gettable properties can be used to satisfy any requirements.

Property requirements are always defined as var, not let. You define the property as either read-only or read-write by adding either the get function or both get and set functions in braces after the type declaration.

protocol SomeProtocol {

    // Your protocol requirements

    var readwriteProperty : Int { set get}

    var readonlyProperty : Int { get }

}

To define a type property, you prefix the property with the class keyword, even when you use the protocol for structures and enumerations.

Note

This rule applies to structures and enumeration types where you use the static keyword.

protocol AnotherProtocol {

    class var typeProperty : Int { get set }

}

struct SomeStruct : SomeProtocol, AnotherProtocol {

    var readwriteProperty : Int

    private(set) var readonlyProperty : Int

    static var typeProperty : Int {

        get {

        return 0

        }

        set {

        }

    }

}

That was a simple example showing how to conform a structure to your protocols. But it doesn’t really help us; let’s look at a concrete example of how this works:

protocol FullName {

    var fullName : String { get }

}

struct Person : FullName {

    var lastName : String

    var firstName : String

    var middleName : String?

    init (firstName : String, lastName : String) {

        self.lastName = lastName

        self.firstName = firstName

    }

    var fullName : String {

        return firstName + (middleName == nil ? "" : " " + middleName!) + " " + lastName

    }

}

var alan = Person(firstName: "Alan", lastName: "Turing")

println(alan.fullName)

alan.middleName = "Mathison"

println(alan.fullName)

Methods

The most common requirements for a protocol are specific instance and type methods. You define the methods in a protocol as you’d define them in a type but without the implementation, that is, without the curly braces.

Note

When defining a method requirement, you can’t specify defaults values for method parameters.

Similar to the property requirement, you use the keyword class when defining type methods, even when they are implemented in structures and enumerations with the static keyword.

The following example shows a protocol that requires two methods, an instance method and a type method. Neither of these methods takes any arguments or has a return value.

protocol MethodProtocol {

    func instanceMethod ()

    class func typeMethod ()

}

If your methods will modify the state of a structure or enumeration type, you have to specify that with mutating keyword:

protocol MethodProtocol {

    mutating func instanceMethod ()

    class func typeMethod ()

}

Initializers

Protocols can require a specific initializer to be implemented by a conforming class. You define these initializers in the protocol just as with regular initializers, but without the curly braces.

protocol SomeProtocol {

    init(parameter : Double)

}

The conforming class can implement these as either convenience or designated initializers. In either case the implementation of the initializer must be marked using the required modifier.

class SomeClass : SomeProtocol {

    required init(parameter: Double) {

    }

}

The required modifier is necessary to ensure that the conforming class provides an explicit or inherited implementation of the initializer on all of its subclasses so they conform to the protocol as well.

Note

You don’t need to provide the required keyword for an initializer if the class is marked as final.

If the subclass overrides a designated initializer and also implements the matching initializer requirements from a protocol, then both the required and override keywords must be used to properly satisfy both requirements.

class ParentClass {

    init(parameter : Double) {

    }

}

class SomeClass : ParentClass, SomeProtocol {

    required override init(parameter: Double) {

    }

}

You can also require failable initializers in your protocol. A failable initializer requirement can be satisfied by either a failable or nonfailable initializer. For a nonfailable initializer, you can use a failable initializer and explicitly unwrap it.

Protocols as Types

When you define a protocol, it becomes a type that can be used much like any other type, even though the protocol doesn’t provide its own implementation.

Protocol types can be used as:
  • Parameter types for methods.

  • Return types for methods.

  • A type for a constant, variable or property.

  • A type for an item in an array, dictionary, or other container.

class SomeClass {

    var protocolConformingProperty : SomeProtocol

    init(someObject : SomeProtocol) {

        self.protocolConformingProperty = someObject

    }

}

var myClass = SomeClass (someObject: SomeStruct(readwriteProperty: 5, readonlyProperty: 10))

println(myClass.protocolConformingProperty.readonlyProperty)

In this example, SomeClass has a property that conforms to a protocol, and the init method has the object that the class is initialized with as the same protocol type.

Delegation

If you’ve been an iOS or OSX developer for any length of time, you’ve no doubt used tableviews, which have one property called delegate. Delegate is a design pattern that delegates or offloads some of the work to an instance of another type that’s better suited to it.

The following example defines a simple protocol for a download manager. It defines two methods to start and end a download.

public protocol DownloadManagerDelegate : NSObjectProtocol {

    func downloadManagerDidStart(manager : DownloadManager)

    func downloadManagerDidEnd(manager : DownloadManager)

}

public class DownloadManager

{

    public weak var delegate : DownloadManagerDelegate?

    init() {

        println("init")

    }

    public func GET(path : String, parameters : [String : AnyObject]? = nil) {

        self.delegate?.downloadManagerDidStart(self)

        // do you work

        self.delegate?.downloadManagerDidEndself)

    }

}

My view controller will adopt the protocol to keep track of the start and end of the network calls I’ll be making. To use it in my controller, I need to implement the required methods:

class ViewController: UIViewController, DownloadManagerDelegate

{

    private var downloadManager : DownloadManager?

    override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view, typically from a nib.

        self.downloadManager = DownloadManager()

        self.downloadManager?.delegate = self

        self.downloadManager?.GET("/articles")

    }

    func downloadManagerDidStart(manager: DownloadManager) {

        println("Download did start.")

    }

    func downloadManagerDidEnd(manager: DownloadManager) {

        println("Download did finish.")

    }

}

Conformance with Extensions

If you have an existing type that you’d like to conform to a protocol, you can do that by implementing the protocol requirements in the extension.

Protocols and Collection Types

A protocol type can be a member of a collection type, such as an array or dictionary. As you know, once a protocol is defined it becomes a first-class type object, and you can simply use it in place of values:

let items[SomeProtocol] = [object1, object2, object3]

This example shows that items is a collection of objects that conform to SomeProtocol; this is one way to store heterogeneous objects. Objects don’t have to be of the same type as long as they conform to the protocol you want.

Protocol Inheritance

Protocols can inherit from one or more parent protocols, as you saw with the DownloadManagerDelegate protocol that inherits from NSObjectProtocol. The syntax is similar to that of class inheritance, but allows listing of multiple parent protocols.

protocol SomeProtocol : ParentProtocol {

}

protocol SomeOtherProtocol : ParentProtocol, AnotherParentProtocol {

}

You can limit the protocol to be used with classes only, and not structures or enumerations, by adding the class keyword before the list of parent protocols. Both of the following examples limit the use MyProtocol to reference types and not value types:

protocol MyProtocol : class {

}

protocol MyProtocol : class, NSObjectProtocol {

}

Protocol Composition

Sometimes you want to be able to require a type to conform to multiple protocols. Swift provides a protocol composition construct that lets you do this. Instead of using the protocol type as the type of the variable, you replace it with a composition having the format protocol<SomeProtocol, AnotherProtocol>, which will create a temporary local protocol that combines all the listed protocols.

func myFunction(parameter : protocol <SomeProtocol, AnotherProtocol>) {

}

This function’s parameter is required to conform to all of the protocols. In this case, if the instance of the type doesn’t conform to both protocols it will be rejected.

Summary

In this chapter, I introduced the concept of protocols. You define a protocol by listing a set of methods inside a protocol block. Objects adopt this protocol by including the protocol name after the colon when defining a type. When an object adopts a formal protocol, it promises to implement every required method that’s listed in the protocol. The compiler helps you keep your promise by giving you an error if you don’t implement all the protocol’s methods.

Copyright information

© Waqar Malik 2015

Authors and Affiliations

  • Waqar Malik
    • 1
  1. 1.CAUnited States

Personalised recommendations