In my project I have few view controllers which are subclasses of UITableViewController, UIViewController, on each I want to implement this behavior:
When user taps outside of a text field it should dismiss the keyboard which was visible when user tapped inside it.
I can easily implement it by defining a tap gesture recognizer and associating a selector to dismiss the keyboard:
class MyViewController {
override func viewDidLoad() {
super.viewDidLoad()
configureToDismissKeyboard()
}
private func configureToDismissKeyboard() {
let tapGesture = UITapGestureRecognizer(target: self, action: "hideKeyboard")
tapGesture.cancelsTouchesInView = true
form.addGestureRecognizer(tapGesture)
}
func hideKeyboard() {
form.endEditing(true)
}
}
Since I have to implement same behavior in multiple view controllers, I am trying to identify a way to avoid using repetitive code in multiple classes.
One option for me is to define a BaseViewController
, which is subclass of UIViewController
, with all above methods defined within it and then subclass each of my view controller to BaseViewController
. The problem with this approach is that I need to define two BaseViewController
s one for UIViewController
and one for UITableViewController
since I am using subclasses of both.
The other option which I am trying to use is - Protocol-Oriented Programming
. So I defined a protocol:
protocol DismissKeyboardOnOutsideTap {
var backgroundView: UIView! { get }
func configureToDismissKeyboard()
func hideKeyboard()
}
Then defined its extension:
extension DismissKeyboardOnOutsideTap {
func configureToDismissKeyboard() {
if let this = self as? AnyObject {
let tapGesture = UITapGestureRecognizer(target: this, action: "hideKeyboard")
tapGesture.cancelsTouchesInView = true
backgroundView.addGestureRecognizer(tapGesture)
}
}
func hideKeyboard() {
backgroundView.endEditing(true)
}
}
In my view controller I confirmed to the protocol:
class MyViewController: UITableViewController, DismissKeyboardOnOutsideTap {
var backgroundView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// configuring background view to dismiss keyboard on outside tap
backgroundView = self.tableView
configureToDismissKeyboard()
}
}
Problem is - above code is crashing with exception:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MyProject.MyViewController hideKeyboard]: unrecognized selector sent to instance 0x7f88c1e5d700'
To avoid this crash I need to redefine hideKeyboard
function within MyViewController
class, which is defeating my purpose of avoiding repetitive code :(
Please suggest if I am doing any thing wrong over here or is there any better way to implement my requirement.