Easy Tutorial
❮ Swift For Loop Swift Dictionaries ❯

Swift Protocols

Protocols define the methods and properties required to implement a specific functionality.

Any type that satisfies the requirements of a protocol is said to conform to that protocol.

Classes, structures, or enumeration types can conform to a protocol and provide concrete implementations to fulfill the methods and functionalities defined by the protocol.

Syntax

The syntax for defining a protocol is as follows:

protocol SomeProtocol {
    // Protocol contents
}

To make a class conform to a protocol, the protocol name is added after the type name, separated by a colon :, as part of the type definition. When conforming to multiple protocols, they are separated by commas ,.

struct SomeStructure: FirstProtocol, AnotherProtocol {
    // Structure contents
}

If a class conforms to a protocol and also has a superclass, the superclass name should precede the protocol names, separated by a comma.

class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
    // Class contents
}

Property Requirements

Protocols specify particular instance or class properties without specifying whether they are stored or computed properties. Additionally, they must indicate whether the properties are read-only or read-write.

Variables are typically declared in protocols using var, and the property is marked as read-write with { set get } after the type declaration, or read-only with { get }.

protocol classa {

    var marks: Int { get set }
    var result: Bool { get }

    func attendance() -> String
    func markssecured() -> String

}

protocol classb: classa {

    var present: Bool { get set }
    var subject: String { get set }
    var stname: String { get set }

}

class classc: classb {
    var marks = 96
    let result = true
    var present = false
    var subject = "Swift Protocols"
    var stname = "Protocols"

    func attendance() -> String {
        return "The \(stname) has secured 99% attendance"
    }

    func markssecured() -> String {
        return "\(stname) has scored \(marks)"
    }
}

let studdet = classc()
studdet.stname = "Swift"
studdet.marks = 98
studdet.markssecured()

print(studdet.marks)
print(studdet.result)
print(studdet.present)
print(studdet.subject)
print(studdet.stname)

The output of the above program is:

98
true
false
Swift Protocols
Swift

Mutating Method Requirements

Sometimes it is necessary to modify the instance of the type within the method.

For instance, for value types (structures, enumerations), the mutating keyword is used as a prefix before func to indicate that the method can modify the instance it belongs to and its properties.

protocol daysofaweek {
    mutating func show()
}

enum days: daysofaweek {
    case sun, mon, tue, wed, thurs, fri, sat
    mutating func show() {
        switch self {
        case .sun:
            self = .sun
            print("Sunday")
        case .mon:
            self = .mon
            print("Monday")
        case .tue:
            self = .tue
            print("Tuesday")
        case .wed:
            self = .wed
            print("Wednesday")
        case .thurs:
            self = .thurs
            print("Thursday")
        case .fri:
            self = .fri
            print("Friday")
        case .sat:
            self = .sat
            print("Saturday")
        }
    }
}
switch self {
    case .thurs:
        self = .thurs
        print("Wednesday")
    case .fri:
        self = .fri
        print("Friday")
    case .sat:
        self = .sat
        print("Saturday")
    default:
        print("NO Such Day")
}

The above program execution output is:

Wednesday

Protocol Constructor Requirements

Protocols can require conforming types to implement specific constructors.

You can write constructor declarations in the protocol definition as if you were writing a regular constructor, but without the curly braces and the constructor body. The syntax is as follows:

protocol SomeProtocol {
    init(someParameter: Int)
}

Example

protocol TCPProtocol {
    init(aprot: Int)
}

Protocol Constructor Requirements Implementation in Classes

You can implement constructors in a class that conforms to a protocol, specifying them as either designated or convenience constructors. In both cases, you must mark the constructor implementation with the "required" modifier:

class SomeClass: SomeProtocol {
    required init(someParameter: Int) {
        // Constructor implementation
    }
}

protocol TCPProtocol {
    init(aprot: Int)
}

class TCPClass: TCPProtocol {
    required init(aprot: Int) {
    }
}

Using the required modifier ensures that all subclasses that conform to the protocol also provide an explicit or inherited implementation of the constructor requirement.

If a subclass overrides a designated constructor from its superclass and that constructor also conforms to a protocol requirement, then the constructor implementation needs to be marked with both the required and override modifiers:

protocol TCPProtocol {
    init(no1: Int)
}

class MainClass {
    var no1: Int // local variable
    init(no1: Int) {
        self.no1 = no1 // initialization
    }
}

class SubClass: MainClass, TCPProtocol {
    var no2: Int
    init(no1: Int, no2: Int) {
        self.no2 = no2
        super.init(no1: no1)
    }
    // Required by protocol and overridden from superclass
    required override convenience init(no1: Int) {
        self.init(no1: no1, no2: 0)
    }
}
let res = MainClass(no1: 20)
let show = SubClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(show.no1)")
print("res is: \(show.no2)")

The above program execution output is:

res is: 20
res is: 30
res is: 50

Protocol Types

Although protocols do not implement any functionality themselves, they can be used as types.

Protocols can be used like any other ordinary types in various scenarios:

Example

protocol Generator {
    associatedtype members
    func next() -> members?
}

var items = [10, 20, 30].makeIterator()
while let x = items.next() {
    print(x)
}

for lists in [1, 2, 3].map({ i in i * 5 }) {
    print(lists)
}

print([100, 200, 300])
print([1, 2, 3].map({ i in i * 10 }))

The above program execution output is:

10
20
30
5
10
15
[100, 200, 300]
[10, 20, 30]

Adding Protocol Members in Extensions

We can extend existing types (classes, structures, enumerations, etc.) through extensions.

Extensions can add properties, methods, subscripts, protocols, and other members to existing types.

protocol AgeClassificationProtocol {
   var age: Int { get }
   func ageType() -> String
}

class Person {
   let firstName: String
   let lastName: String
   var age: Int
   init(firstName: String, lastName: String) {
      self.firstName = firstName
      self.lastName = lastName
      self.age = 10
   }
}

extension Person: AgeClassificationProtocol {
   func fullName() -> String {
      var c: String
      c = firstName + " " + lastName
      return c
   }

   func ageType() -> String {
      switch age {
      case 0...2:
         return "Baby"
      case 2...12:
         return "Child"
      case 13...19:
         return "Teenager"
      case let x where x > 65:
         return "Elderly"
      default:
         return "Normal"
      }
   }
}

Protocol Inheritance

Protocols can inherit one or more other protocols and can add new requirements on top of the inherited protocols.

protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
    // protocol definition
}

Example

protocol ClassA {
    var no1: Int { get set }
    func calc(sum: Int)
}

protocol Result {
    func print(target: ClassA)
}

class Student2: Result {
    func print(target: ClassA) {
        target.calc(1)
    }
}

class ClassB: Result {
    func print(target: ClassA) {
        target.calc(5)
    }
}

class Student: ClassA {
    var no1: Int = 10

    func calc(sum: Int) {
        no1 -= sum
        print("学生尝试 \(sum) 次通过")

        if no1 <= 0 {
            print("学生缺席考试")
        }
    }
}

class Player {
    var stmark: Result!

    init(stmark: Result) {
        self.stmark = stmark
    }

    func print(target: ClassA) {
        stmark.print(target)
    }
}

var marks = Player(stmark: Student2())
var marksec = Student()

marks.print(marksec)
marks.print(marksec)
marks.print(marksec)
marks.stmark = ClassB()
marks.print(marksec)
marks.print(marksec)
marks.print(marksec)

The output of the above program is:

学生尝试 1 次通过
学生尝试 1 次通过
学生尝试 1 次通过
学生尝试 5 次通过
学生尝试 5 次通过
学生缺席考试
学生尝试 5 次通过
学生缺席考试

Class-Only Protocols

You can limit a protocol to be adopted only by class types by adding the class keyword in the protocol's inheritance list.

The class keyword must be the first in the protocol's inheritance list, followed by any other inherited protocols. The format is as follows:

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
    // class-only protocol definition
}
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
    // Protocol definition
}

Example

protocol TcpProtocol {
    init(no1: Int)
}

class MainClass {
    var no1: Int // Local variable
    init(no1: Int) {
        self.no1 = no1 // Initialization
    }
}

class SubClass: MainClass, TcpProtocol {
    var no2: Int
    init(no1: Int, no2: Int) {
        self.no2 = no2
        super.init(no1: no1)
    }
    // Required by protocol, overridden from superclass
    required override convenience init(no1: Int) {
        self.init(no1: no1, no2: 0)
    }
}

let res = MainClass(no1: 20)
let show = SubClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(show.no1)")
print("res is: \(show.no2)")

Output of the above program is:

res is: 20
res is: 30
res is: 50

Protocol Composition

Swift supports combining multiple protocols, which is useful when you need to conform to several protocols at once.

Syntax format is as follows:

protocol Stname {
    var name: String { get }
}

protocol Stage {
    var age: Int { get }
}

struct Person: Stname, Stage {
    var name: String
    var age: Int
}

func show(celebrator: Stname & Stage) {
    print("\(celebrator.name) is \(celebrator.age) years old")
}

let studname = Person(name: "Priya", age: 21)
print(studname)

let stud = Person(name: "Rehan", age: 29)
print(stud)

let student = Person(name: "Roshan", age: 19)
print(student)

Output of the above program is:

Person(name: "Priya", age: 21)
Person(name: "Rehan", age: 29)
Person(name: "Roshan", age: 19)

Checking for Protocol Conformance

You can use the is and as operators to check for protocol conformance or to force downcast to a specific type.

Example

The following example defines a HasArea protocol, requiring a readable area of type Double:

protocol HasArea {
    var area: Double { get }
}

// Circle class conforms to the HasArea protocol
class Circle: HasArea {
    let pi = 3.1415927
    var radius: Double
    var area: Double { return pi * radius * radius }
    init(radius: Double) { self.radius = radius }
}

// Country class conforms to the HasArea protocol
class Country: HasArea {
    var area: Double
    init(area: Double) { self.area = area }
}

// Animal class does not conform to the HasArea protocol
class Animal {
    var legs: Int
    init(legs: Int) { self.legs = legs }
}

let objects: [AnyObject] = [
    Circle(radius: 2.0),
    Country(area: 243_610),
    Animal(legs: 4)
]

for object in objects {
    if let objectWithArea = object as? HasArea {
        print("Area is \(objectWithArea.area)")
    } else {
        print("Something that doesn't have an area")
    }
}

Output of the above program is:

Area is 12.5663708
Area is 243610.0
Something that doesn't have an area
Circle(radius: 2.0),
Country(area: 243_610),
Animal(legs: 4)
]

for object in objects {
    // Check each element to see if it conforms to the HasArea protocol
    if let objectWithArea = object as? HasArea {
        print("Area is \(objectWithArea.area)")
    } else {
        print("No area")
    }
}

The output of the program execution is:

Area is 12.5663708
Area is 243610.0
No area
❮ Swift For Loop Swift Dictionaries ❯