Swift NSNotificationCenter observer when class extension fails

I tried to create a universal mechanism that could respond to a keyboard that displays and hides in iOS. I came up with a simple protocol and its extension, which does not contain real animations, but pulls them out of the object that accepts this protocol:

import UIKit

protocol KeyboardAnimatable {
    func keyboardWillShowAnimation() -> (() -> Void)?
    func keyboardWillHideAnimation() -> (() -> Void)?
}

extension KeyboardAnimatable where Self: UIViewController {

    func setupKeyboardNotifcationListeners() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
    }

    func removeKeyboardNotificationListeners() {
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
    }

    func keyboardWillShow(notification: NSNotification) {
        let userInfo = notification.userInfo as! Dictionary<String, AnyObject>
        let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSTimeInterval
        let animationCurve = userInfo[UIKeyboardAnimationCurveUserInfoKey]!.intValue
        let curveAnimationOption = UIViewAnimationOptions(rawValue: UInt(animationCurve))
        let options: UIViewAnimationOptions = [.BeginFromCurrentState, curveAnimationOption]

        if let animation = keyboardWillShowAnimation() {
            UIView.animateWithDuration(animationDuration, delay: 0, options: options, animations: animation, completion: nil)
        }
    }

    func keyboardWillHide(notification: NSNotification) {
        let userInfo = notification.userInfo as! Dictionary<String, AnyObject>
        let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSTimeInterval
        let animationCurve = userInfo[UIKeyboardAnimationCurveUserInfoKey]!.intValue
        let curveAnimationOption = UIViewAnimationOptions(rawValue: UInt(animationCurve))
        let options: UIViewAnimationOptions = [.BeginFromCurrentState, curveAnimationOption]

        if let animation = keyboardWillHideAnimation() {
            UIView.animateWithDuration(animationDuration, delay: 0, options: options, animations: animation, completion: nil)
        }
    }

}

I explicitly use the sentence wherein extension KeyboardAnimatable where Self: UIViewControllerto narrow it down so I can use it selfwhen adding watchers. Now I can create a view controller that accepts this protocol and, for example, changing the restrictions when the keyboard appears:

import UIKit

class ViewController: UIViewController, KeyboardAnimatable {

    @IBOutlet weak var constraintYCenter: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
        setupKeyboardNotifcationListeners()
    }

    func keyboardWillShowAnimation() -> (() -> Void)? {
        return {
            self.constraintYCenter.constant = 100
            self.view.layoutIfNeeded()
        }
    }

    func keyboardWillHideAnimation() -> (() -> Void)? {
        return nil
    }

//    func keyboardWillShow(notification: NSNotification) {
//        print("will show")
//    }
//    
//    func keyboardWillHide(notification: NSNotification) {
//        print("will hide")
//    }

    deinit {
        removeKeyboardNotificationListeners()
    }
}

But when I run this code, the application crashes with the following error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', 
reason: '-[KeyboardAnimatableDemo.ViewController keyboardWillShow:]: 
unrecognized selector sent to instance 0x7fb429f192d0'

, keyboardWillShow:, . , ViewController, ( ), .

, - self setupKeyboardNotifcationListeners(), , . func setupKeyboardNotifcationListeners(vc: UIViewController) vc self, .

UIViewController , , . - extension UIViewcontroller where Self: KeyboardAnimatable, , , Swift.

- - , ?

+4
1
+1

Source: https://habr.com/ru/post/1618097/


All Articles