Swift NSNotificationCenter观察者在类扩展中崩溃

时间:2015-12-01 10:55:57

标签: ios swift protocols nsnotificationcenter

我尝试创建一种通用机制,可以对iOS中的键盘显示和隐藏做出反应。我提出了简单的协议及其扩展,它不包含真实动画,但是从采用该协议的对象中提取它们:

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)
        }
    }

}

我在where中明确使用extension KeyboardAnimatable where Self: UIViewController子句缩小范围,以便在添加观察者时可以使用self。 现在我可以创建一个采用这种协议的视图控制器,例如键盘出现时更改约束:

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()
    }
}

但是当我运行此代码时,应用程序崩溃并出现以下错误:

*** 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中甚至可能不可能。

有没有人试图取得类似的成就,他成功了?

1 个答案:

答案 0 :(得分:1)

我通过删除协议并引入&#34; empty&#34;解决了这个问题。这些方法的实施。现在Extension用于键盘直接扩展UIViewController,因此它应该非常容易使用。

代码依旧:https://gist.github.com/AdamSliwakowski/6fa1e920254ce584d203