Q:

Crash in viewDidLoad() when registering observers

I've a crash occurring in viewDidLoad. I'm not able to figure out why it's happening. Below is crash trace and all the code.

class WriteTestimonialViewController: UIViewController, UITextViewDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addPurpleBackground()

        title = "Write Testimonial"

        testimonialTextView.clearTextView(text: "Type testimonial")

        // Setup keyboard event
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
        // Dismiss keyboard
        self.hideKeyboardWhenTappedAround()
    }

    // Setup keyboard event
    @objc func keyboardWillShow(notification:NSNotification){
        var userInfo = notification.userInfo!
        var keyboardFrame:CGRect = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
        keyboardFrame = self.view.convert(keyboardFrame, from: nil)

        var contentInset:UIEdgeInsets = self.scrollView.contentInset
        contentInset.bottom = keyboardFrame.size.height
        scrollView.contentInset = contentInset
    }

    @objc func keyboardWillHide(notification:NSNotification){

        let contentInset:UIEdgeInsets = UIEdgeInsets.zero
        scrollView.contentInset = contentInset
    }

 }

extension UIViewController {

    // Dismiss keyboard on touch
    func hideKeyboardWhenTappedAround() {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
        tap.cancelsTouchesInView = false
        view.addGestureRecognizer(tap)
    }

    @objc func dismissKeyboard() {
        view.endEditing(true)
    }
}

func addPurpleBackground() {
    let imageViewBackground = UIImageView()
    imageViewBackground.image = UIImage(named: "bgimage")

    imageViewBackground.contentMode = .scaleAspectFill
    imageViewBackground.clipsToBounds = true
    imageViewBackground.translatesAutoresizingMaskIntoConstraints = false

    self.insertSubview(imageViewBackground, at: 0)

    self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|[imageViewBackground]|",
                                                       options: [],
                                                       metrics: nil,
                                                       views: ["imageViewBackground": imageViewBackground]))
    self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[imageViewBackground]|",
                                                       options: [],
                                                       metrics: nil,
                                                       views: ["imageViewBackground": imageViewBackground]))
}

A:

I think would be better to register for notifications in viewWillAppear/viewDidAppear, you would be interested in the notifications only if the view is actually displayed. If you keep it in viewDidLoad can happen sometimes that the view has been loaded but is not immediately appeared on the screen.
Also From iOS 9 you don't need anymore to manually remove observer.

In OS X 10.11 and iOS 9.0 NSNotificationCenter and
  NSDistributedNotificationCenter will no longer send notifications to
  registered observers that may be deallocated

