Swift: Protocols

Swift: Protocols

Please find the GitHub link of all the code here.

Protocols are used to create the loosely coupled system. With protocols, we define the contracts based on which two layers or components of the system can communicate with each other.

Loose coupling is actually implemented by avoiding the composition of concrete objects. Instead, the composition is done with help of abstract types.

Now let's create a protocol with the associated types. This helps us create protocols with generic types.

protocol Employable {

    associatedtype Item

    var firstName: Item {get set}
    var fullName: Item {get} 
}        

In the example above Item is the associated type (Generic) whose concrete type would be defined later.

Implementation of the protocol with String being the concrete type.

class Employee: Employable {

    //Concrete type defined
    typealias Item = String
    
    //Properties
    var reportees = Array<String>()
    var firstName: String
    var fullName: String {
        return "Mr. " + firstName
    }
    
    init(_ name: String) {
        firstName = name
    }
}
        

  • With Protocol Inheritance, we can add the methods to the existing protocol.

protocol EmployeeProto: Employable { 
    func getSalary() -> Int
}        

  • We can compose two or more protocols into one with protocol composition.

typealias MultipleProtocols = Employable & Deployable        

  • We can check the protocol conformance with the code below.

if let employee = employee as? MultipleProtocols        

  • AnyObject vs Any: Objective C did not have value types however swift does have value types. So type conversion from ObjC reference type to Swift value type was problematic.
  • AnyObject: Represents only class types.
  • Any: Represents both class struct and function types.
  • class vs AnyObject: As per apple documentation both are the same however any object should be the preferred way of creating the class-only protocols.
  • Class-only protocols: In order to work with delegation patterns without creating memory leaks, it's important that delegates are implemented with reference types only. And hence we impose the constraint via class-only protocols.

protocol someClassOnly: AnyObject {
    func addToList(_ item: String)
}        

  • Default Implementations: We can create the extensions of the protocol to add the default implementation of the method.

extension someClassOnly {
    func addToList(_ item: String) {
        print("Default Implementation of addToList")
    }
}        

  • Optional Protocol: We can use @objc protocols to add the optional methods in it.

@objc protocol Countable {
    @objc optional func displayCount()
}        

Implementing Equatable protocol: We need to implement an equatable protocol in order to define how two objects need to be equated.

struct Car: Equatable {

? ? let make: String

? ? static func == (lhs: Car, rhs: Car) -> Bool {

? ? ? ? return lhs.make == rhs.make

? ? }

}        

Implementing Comparable Protocol: We need to implement a comparable protocol in order to define how two objects need to be compared.

struct Student: Comparable {

? ? static func < (lhs: Student, rhs: Student) -> Bool {

? ? ? ? return lhs.marks < rhs.marks

? ? }

?? ?

? ? let name: String

? ? let marks: Double

}        

Implementing Hashable Protocol: Defines how an object can be stored as a Key-Value pairing.

struct Person 
    let name: String
}

struct Account: Hashable {
    
    static func == (lhs: Account, rhs: Account) -> Bool {
        return lhs.account.name == rhs.account.name
    }
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(account.name)
    }
    
    let account: Person
}        

Opaque Types: Some concrete implementations would be returned from this function at the time of execution. Returning with the keyword "some" is known as opaque type.

Implementing Sequence and Iterator Protocols: To create your own sequence.

  • Implement the sequence protocol and override the makeIterator() method to return some IteratorProtocol.

struct CountDown: Sequence {

    let start: Int

    //some 
    func makeIterator() -> some IteratorProtocol {
        MyIterator(self)
    }
}        

  • Now let's implement the IteratorProtocol which is required by our sequence and implement the next() method.

struct MyIterator: IteratorProtocol {

    let countdown: CountDown
    var currentValue: Int
    
    init(_ cntd: CountDown) {
        countdown = cntd
        currentValue = countdown.start
    }
    
    //next - Needs to be implemented
    mutating func next() -> Int? {
        currentValue -= 1
        return currentValue >= 0 ? currentValue : nil
    }
}        

  • This is how our implementation would work, we can use the "in" operator with our class since it's a sequence.

func demo() 

? ? let coutDown = CountDown(start: 10)

? ? for count in coutDown {

? ? ? ? print(count)

? ? }

}        

要查看或添加评论,请登录

Christo Abhinav Kumar的更多文章

  • Swift: Initializers

    Swift: Initializers

    This post explores all you need to know about initializers in swift. Please find all relevant code here.

  • Swift: Connect with API using Async Await

    Swift: Connect with API using Async Await

    The sample code below shows the non-reactive ways to connect with an API endpoint using async-await. The code is a…

社区洞察

其他会员也浏览了