Victor Jonah I am a Software Developer with over three years of experience working with JavaScript and its frameworks. I currently work as a remote software developer for a tech agency.

Understanding protocols in Swift

3 min read 969

Understanding Protocols in Swift

When Apple announced the release of Swift, the first protocol-oriented language, at their Worldwide Developers Conference (WWDC) in 2015, it indicated a shift away from their existing object-oriented programming, Objective-C.

But because Objective-C utilizes implicit sharing inheritance, creating new objects becomes a slow process, and the new objects often have functionalities that are unneeded. In this case, if a class hierarchy is complex, maintaining it can cause problems like inefficiency and race conditions.

With Swift’s protocol paradigm, developers can now build objects without inheritance, objects can be used by existing code, and a single class can work with multiple protocols without the need for inheritance.

In this post, we’ll discuss Swift’s protocol paradigm and its advantages. Knowledge of object-oriented programming is helpful for understanding this post’s content.

What are protocols and how do they work in Swift?

Generally, a protocol:

  • Is a blueprint that a class or struct follows
  • Is a communication contract for unrelated objects to rely on
  • Defines methods and values

To understand how protocols work in Swift, let’s suppose we are building application software and must model the requirements to satisfy the application. We can either begin with a superclass and mold the relationship through inheritance or start with a protocol and mold the relationship through the implementation.

If we want to build a salary remittance system for our app and we have an Employee class, using a protocol looks like the following:

protocol EmployeeProtocol {
    var emplname: String { get }
    var description: String { get }
    var salary: Int { get set }
    func paySalary(salary: Int) -> String
}

Usually, if we use get, we can make it a const, var, let, or computed property. However, using the property declaration get set for the salary property limits var salary: Int { get set } to var.

If we want to write a class that follows this protocol, such as the Employee class, we have the following:

class Employee: EmployeeProtocol {
    var emplname: String = "Victor Jonah"

    var description: String = "Software Engineer"

    var salary: Int = 5000

    func paySalary(salary: Int) -> String {
        return "Salary disbursed to {emplname}"
    }
}

In summary, protocols allow us to group our methods, properties, and functions. However, these protocols can only conform to classes, enums, and structs.

More than one protocol can conform to one object, but they must be separated by commas:

struct Player: MainPlayer, EnemyPlayer {
   // code definition 
}

Also, if a class has a superclass, we can define any protocols after the superclass name:

class TheClass: ItsSuperclass, FirstProtocol, SecondProtocol {
  // class definition goes here
}

We can use enum with our protocols for computed properties, but they do not work for stored properties:

enum Employer: EmployerProtocol {
  var name: String { 
    return "Alex"
  }

  var description: String {
    return "CEO"
  }

  var salary: Int {
    get {
      return 
    }
  }
}

Swift also throws an error at the compile time if the protocol does not conform to the class, struct, or enum.

A Swift mobile protocol example

Let’s see a more common use case for the protocol with a mobile example:

protocol Mobile {
    var name: String { get }
    var iEMICode: Int { get }
    var sIMCard: String { get }
    var processor: String { get }
    var internalMemory: Int { get}
    var isSingleSIM: Bool { get }

    mutating func GetIEMICode() -> String

    func SendMessage() -> String

    func Dial() -> String

    func Receive() -> String

    init(name: String)
}

struct Apple: Mobile {
    var name: String = "Apple"

    init(name: String) {
        self.name = name
    }
    var iEMICode: Int  = 3244332

    var sIMCard: String = "Vodaphone"

    var processor: String = "Snapdragon"

    var internalMemory: Int = 213424

    var isSingleSIM: Bool = true

    mutating func GetIEMICode() -> String {
        return "IEMEICode"
    }

    func SendMessage() -> String {
       return "Message sent"
    }

    func Dial() -> String {
        return "Dialed"
    }

    func Receive() -> String {
        return "Receiving call"
    }  
}

struct Samsung: Mobile {
    var name: String = "Samsung"

    init(name: String) {
        self.name = name
    }

    var iEMICode: Int = 3243433

    var sIMCard: String = "TMobile"

    var processor: String = "Snapdragon"

    var internalMemory: Int = 324432

    var isSingleSIM: Bool = false

    func GetIEMICode() -> String {
        return "IEMEICode"
    }

    func SendMessage() -> String {
        return "Message sent"
    }

    func Dial() -> String {
        return "Dialed"
    }

    func Receive() -> String {
       return "Receiving call"
    }
}

Notice that the mutating keyword on line 9 works when we have an object that must change one of its properties. We must specify that GetIEMICode() is a mutating method in our protocol. In our struct, we must also specify the keyword mutating but not in the class.

Advantages of protocols in Swift

From the above examples, we can see why protocols are useful and why Swift uses the protocol-oriented paradigm. The advantages of using protocols manifest in the following ways:

Code clarity

Naming protocols provides a better understanding of their instances. In our first example, we created an EmployeeProtocol that conforms to the Employee class, showing how protocols offer meaning to classes, enums, or structs.

As Dave Abrahams said at the 2015 WWDC, “Don’t start with a class, start with a protocol.”

Reusability

With protocol extensions, we can have a default implementation for our method in the class, enum, or struct they conform to. We can see this in the code below:

protocol Person {
    var name: String { get }
    var age: Int { get }
    var gender: String { get }

    func speak()
}

extension Person {
    func speak() {
        print("Hello, this works!")
    }
}

class Male: Person {
    var name: String = ""

    var age: Int = 23

    var gender: String = "Male"
}

struct Female: Person {
    var name: String

    var age: Int

    var gender: String
}

By creating a default functionality using the extension keyword on line 9, we do not need to repeat it in our class or struct.

Separation of classes

Protocols also eliminate the need for classes, enums, and structs to be dependent on each other because they do not use inheritance.



Conclusion

In summary, protocols in Swift offer communication between unrelated objects where we define the methods and variables observed in classes, enums, and structs. Because Swift embraces the protocol-oriented paradigm, we can model our system before defining classes, structs, or enums, making the process more efficient.

Get setup with LogRocket's modern error tracking in minutes:

  1. Visit https://logrocket.com/signup/ to get an app ID.
  2. Install LogRocket via NPM or script tag. LogRocket.init() must be called client-side, not server-side.
  3. $ npm i --save logrocket 

    // Code:

    import LogRocket from 'logrocket';
    LogRocket.init('app/id');
    Add to your HTML:

    <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
    <script>window.LogRocket && window.LogRocket.init('app/id');</script>
  4. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • ngrx middleware
    • Vuex plugin
Get started now
Victor Jonah I am a Software Developer with over three years of experience working with JavaScript and its frameworks. I currently work as a remote software developer for a tech agency.

Leave a Reply