Thursday, July 12, 2018

Swift Protocol Extensions


Protocol extensions is one of the beautiful features of Swift language.

Let’s see the usefulness with a use case.

I have a Logger protocol which is having simple log function which takes string to be logged and logs it.


       
 protocol Logger {
    func log(message: String)
 }



I am taking 3 service classes which has to confirm to this Logger protocol for logging service errors.

       
 class FacebookServices: Logger {
    func log(message: String) {
        print("Facebook - \(message)")
    }
 }

 class TwitterServices: Logger {
    func log(message: String) {
        print("Twitter - \(message)")
    }
 }

 class InstagramServices: Logger {
    func log(message: String) {
        print("Instagram - \(message)")
    }
 }



All the 3 classes are confirming to Logger protocol and implemented interface method log.

Now, What If we need log a generic error like "Service Unavailable”. 

We need to write that in all the 3 classes or we need to take a base class and keep the logGenericError method there.

       
 class FacebookServices: Logger {
    func log(message: String) {
        print("Facebook - \(message)")
    }
    
    func logGenericError() {
        print("Service unavailable!")
    }
 }

 class TwitterServices: Logger {
    func log(message: String) {
        print("Twitter - \(message)")
    }
    
    func logGenericError() {
        print("Service unavailable!")
    }
 }

 class InstagramServices: Logger {
    func log(message: String) {
        print("Instagram - \(message)")
    }
    
    func logGenericError() {
        print("Service unavailable!")
    }
 }



Instead of this, We can extend the Logger protocol and keep our convenient API there which allows all the classes confirming to the portal can access that extension.

       
 extension Logger {
    func logGenericError() {
        print("Service unavailable!")
    }
 }

 let twitter = TwitterServices()
 let facebook = FacebookServices()

 twitter.log(message: "404")
 twitter.logGenericError() // Service unavailable!

 twitter.log(message: "500")
 twitter.logGenericError()  // Service unavailable!




Easy and very useful Right?

We can customise the logGenericError() If a service needs like shown below.

       
 class InstagramServices: Logger {
    func log(message: String) {
        print("Instagram - \(message)")
    }
    func logGenericError() {
        print("Please try later!")
    }
 }

 let instagram = InstagramServices()
 instagram.logGenericError() // Please try later!



Go with Protocol extensions in such use cases instead of going for base classes.

Hope this post is useful. Feel free to comment incase of any queries.