I have a need for an external Keyboard Manager class since I have multitude of Viewcontrollers that require that service. The code I have written works perfectly when it sits physically inside the Viewcontroller, but once I call it through Keyboard Manager class i get "libc++abi.dylib: terminating with uncaught exception of type NSException".
I know this error normally means that there is some connection broken with the IBOutlet, but in this case I am not sure how this can relate.
The class basically tells the scrollview in viewcontroller that calls it to scroll up and make a textfield visible, restore the state when editing is finished and hide the keyboard when scrollview is tapped. I also tried same approach with KeyboardManagerDelegate, with identical results. I've also tried changing the activeField, vc and scrollView variables to weak in any possible combination but it did not change anything.
Here's the code for KeyboardManager:
import UIKit
class KeyboardManager {
var activeField: UITextField?
var vc: UIViewController!
var scrollView: UIScrollView!
init(_ vc: UIViewController, _ scrollView: UIScrollView, _ activeField: UITextField?) {
self.vc = vc
self.scrollView = scrollView
self.activeField = activeField
NotificationCenter.default.addObserver(vc, selector: #selector(keyboardDidShow), name: .UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(vc, selector: #selector(keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
let tap = UITapGestureRecognizer(target: vc, action: #selector(hideKeyboard))
tap.numberOfTouchesRequired = 1
self.scrollView.addGestureRecognizer(tap)
}
@objc func keyboardDidShow(notification: NSNotification) {
if let activeField = activeField, let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
print("Keyboard height is \(keyboardSize.height)")
let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize.height, right: 0.0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
scrollView.scrollRectToVisible(activeField.frame, animated: true)
}
}
@objc func keyboardWillHide(notification: NSNotification) {
let contentInsets = UIEdgeInsets.zero
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
}
@objc func hideKeyboard() {
activeField?.resignFirstResponder()
}
}
The relavant code in Viewcontroller is here:
class ViewController: UIViewController, UITextFieldDelegate {
weak var activeField: UITextField?
var keyboardManager: KeyboardManager!
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
keyboardManager = KeyboardManager(self, scrollView, activeField)
}
func textFieldDidBeginEditing(_ textField: UITextField) {
self.activeField = textField
}
func textFieldDidEndEditing(_ textField: UITextField) {
self.activeField = nil
}
}
Thanks in advance for any insights on how to get this working as my project is now on hold until I can figure this out, it would be just too much repetition if I would to copy & paste this code into every single Viewcontroller I have.
UPDATE: I just found something interesting that I did not see before in my own project: KeyboardManagerDrama[1731:3465043] Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[KeyboardManagerDrama.ViewController keyboardDidShowWithNotification:]: unrecognized selector sent to instance 0x15fe18790' So Im thinking perhaps it is because im setting the observer to vc but the viewcontroller does not have the selector functions. If this is the case, how can I set the observers to viewcontroller while keeping selector functions in the KeyboardManager?