Protocol oriented programming to the rescue
What is POP?
Protocol oriented programming or simply POP is the new programming paradigm which has some obvious benifits over the traditional object oriented programming. POP was introduced at Apple’s WWDC 2015 developer conference which is a great starting point in to the world of protocol oriented programming. Infact, Apple claims swift to be a protocol oriented language with over 50 protocols in the swift standard library. I strongly recommend to watch the wwdc videos about pop.
At the heart of Swift's design are two incredibly powerful ideas: protocol-oriented programming and first class value…developer.apple.com
Building on last year's Protocol-Oriented Programming and Building Better Apps with Value Types sessions, this year's…developer.apple.com
Where to use POP?
After watching the amazing wwdc videos and lots of other useful resources on the web, i always wanted to implement POP in my day to day coding but couldn’t get the right spot until recently. I’ll explain one of the use case of POP i came across in my app development process. If you are not clear about protocol oriented programming even after watching wwdc videos, well, that’s perfectly fine, even i found it difficult to get a hang of it on the first glance. Please check the references section at the end of this article, for links to some great resources that might really help you to get through POP.
Practical use case for POP:
In one of my recent apps which i’ve been working on, most of the screens in the app had textviews or a textfield as the app functionality heavily relied on the user input data. As the normal case with iOS development, developer have to manually handle the visibility of textfield/textview according to the keyboard changes. So i was doing that in the usual way by registering for keyboard notifications in the viewcontroller wherever there was a textfield/textview. After completing a couple of screens, i found myself repeating the same code over and over in almost every viewcontroller and as a good developer, i should not repeat the code according to DRY principle(Don’t Repeat Yourself)👻.
I thought of abstracting away the keyboard handling logic in to a single place from which i could reuse the same logic over the entire app wherever required. But where would i put that code? I have a base viewcontroller form which all of my viewcontrollers inherits and if i have to put the common code there, it would be available to all the viewcontrollers irrespective of viewcontroller having a textfield or not. This is one of the draw back of object oriented programming where a subclass gets a functionality which it doesn’t actually need. So it didn’t make sense to put the code in base viewcontroller.
Then the idea of POP popped in my mind💡. So, the idea is this, start with a protocol which enforces the conforming types ( class/struct/enum) to implement a method which takes care of the keyboard handling logic. Then i can make only those viewcontrollers which have a textfield/textview to conform to that protocol and implement the keyboard handling method 🙌.
But then i have a problem again, in each and every viewcontroller conforming to the protocol, i need to implement the same keyboard handling method (remember DRY).
Starting with swift 2.0, we can extend a protocol and add a default implementation for the methods defined in the protocol. This is where the true power of swift lies. The conforming classes or structs can fallback on the default implementation provided by protocol extension instead of giving their own implementation. We’ll leverage this power and embed all the keyboard handling logic with in the protocol extension. Let’s start by writing a method which registers/deregisters for keyboard notifications.
If you are clear on what the above code does, then you can skim through the following section. If not, follow along. lets run through the above code step by step.
The function keyboardNotifications(shouldRegister:Bool) is used to register and deregister for keyboard notifications by passing the boolean flag accordingly (true to register and false to deregister).
- I declared two variables of type NSObjectProtocol to hold a reference to observers so that i can remove them as observers when i no longer need them. If you are wondering why the objects were of type NSObjectProtocol, well, you can option-click on addObserver method on line 12 and see that it returns an object of type NSObjectProtocol.
- The if block checks for the shouldRegister flag and if its true, we register for two keyboard notifications, one when keyboard is about to appear on screen and other when keyboard is just about to be dismissed. Please note that i’ve used an overloaded version of addObserver method which takes in a closure instead of a selector.
- If shouldRegister flag is false, then in the else block, we are deregistering for keyboard notifications by removing the observers.
At this point, your swift compiler should be complaining about the missing handler(notification:) method. Before implementing the handler method, we need to supply the handler method with the frame of first responder (the textfield/textview currently being edited) in order to move it in to the visible portion of screen when keyboard comes up. There might be more than one textfield/textviews per screen and passing all those frames would quickly become a mess. Instead we can just pass over the superview which contains all the textfields/textviews present in the screen and from that superview, we can sift through all the subviews until we find a first responder. In most cases, the superview would be either the viewcontroller’s view or a scrollview.
So, How would i pass a view from a viewcontroller to a method which is written in protocol extension? Lets check it out below.
Property requirements in protocol:
In a swift protocol, we can add a property requirement which means, the conforming type (in this case, its our viewcontroller) should have a property whose type is defined in the protocol. Lets add a property requirement to our KeyboardObserver protocol which enforces the conforming viewcontrollers to have a read-only property of type UIView which gives us access to the container view. The code below shows how to do that.
Okay, now that we can access container view from within the protocol extension, we need to find the first responder by checking all the subviews of the container view. Lets write an utility method which takes in a container view and returns the first responder.
The above function recursively searches through all the subviews of the given view for a first responder and returns it. Now lets implement the handler method where the actual keyboard handling logic is written.
When registering for keyboard notifications, the addObserver method was expecting a closure which takes in an argument of type Notification. As functions in swift are just named closures, we’ve supplied a handler function with an argument of type Notification so that, whenever iOS fires a keyboard notification, the above handler method gets invoked. Let’s understand whats going on in the handler function.
- First, we need to get the frame of the keyboard from userInfo dictionary supplied in the Notification. Similarly, we extract keyboard animation duration and notification name from the Notification object and first responder from the container view.
- We begin an UIView animation with the same duration as of keyboard’s animation duration and then we calculate the height of visible portion of the screen by substracting keyboard height from the container view’s height.
- If the keyboard notification is for willShow, we check if its not a scrollview, and firstResponder is being covered by keyboard, we set the transform of the view to vertical offset calculated previously. On the other hand, if the container is a scrollview, we just set the content inset of scrollview to keyboard’s height and use the scrollRectToVisible method of scrollview to bring the first responders frame in to the visible portion.
- If the keyboard notification is for willHide, we reset the transform and content inset of a view and scrollview respectively to its initial values.
Adopting the KeyboardObserver protocol:
We are done with writing the protocol and now let’s see how to adopt the KeyboardObserver protocol in our ViewController.
The above code shows a sample ViewController having one or more textfields/textviews conforming to KeyboardObserver protocol. The ViewController should have a property ‘container’ of type UIView for which we can either return a scrollview or self.view.
In viewWillAppear method, we register for keyboard notifications by passing true to KeyboardNotifications(shouldRegister:) method and in viewWillDisappear method, we deregister for keyboard notifications by passing false to the same method.
Please give it a try and let me know in the comments section if there are any other ways to handle it better.
Check out some good resources on protocol oriented programming in the references section below.
Update Note: This tutorial has been updated to Swift 3.0 by Niv Yahel. The original tutorial was written by Erik Kerber…www.raywenderlich.com
Most modern programming languages, in the hopes of enhanced maintainability and reusability of code, offer some…www.toptal.com
There has been a lot of buzz ever since the 2015 WWDC talk on Protocol Oriented Programming. But the underlying…clean-swift.com
Join me for a Swift Community Celebration 🎉 in New York City on September 1st and 2nd. Use code NATASHATHEROBOT to get…www.natashatherobot.com