扩展非泛型类型的尾随where子句

42

我有以下代码:

func registerNotification(name:String, selector:Selector)
{
    NSNotificationCenter.defaultCenter().addObserver(self, selector: selector, name: name, object: nil)
}

func registerKeyboardNotifications()
{
    let isInPopover = navigationController?.popoverPresentationController != nil
    let ignore = isInPopover && DEVICE_IS_IPAD
    if !ignore {
        registerNotification(UIKeyboardWillShowNotification, selector: Selector("keyboardWillShow:"))
        registerNotification(UIKeyboardWillHideNotification, selector: Selector("keyboardWillHide:"))
    }
}

在对UIViewController进行扩展时,这段代码被许多视图控制器重用以注册键盘通知。但是,在Swift 2.2中,它会产生一个警告。我喜欢新的#selector语法,但不确定如何在这种情况下实现它。

我认为正确的解决方案是创建一个协议,并仅为符合该协议的实例扩展UIViewController。到目前为止,我的代码如下:

@objc protocol KeyboardNotificationDelegate
{
    func keyboardWillShow(notification: NSNotification)
    func keyboardWillHide(notification: NSNotification)
}

extension UIViewController where Self: KeyboardNotificationDelegate
{
    func registerKeyboardNotifications()
    {
        let isInPopover = navigationController?.popoverPresentationController != nil
        let ignore = isInPopover && DEVICE_IS_IPAD
        if !ignore {
            registerNotification(UIKeyboardWillShowNotification, selector: #selector(KeyboardNotificationDelegate.keyboardWillShow(_:)))
            registerNotification(UIKeyboardWillHideNotification, selector: #selector(KeyboardNotificationDelegate.keyboardWillHide(_:)))
        }
    }
}

然而这会让我出现错误

trailing where clause for extension of non-generic type

在扩展行上。有什么想法吗?

2个回答

80

解决方案很简单,只需交换扩展子句中的顺序:

extension UIViewController where Self: KeyboardNotificationDelegate
应该是。
extension KeyboardNotificationDelegate where Self: UIViewController

4
这对我非常有帮助。我之前是这样写的:extension UIViewController where Self: UICollectionViewDelegate,但我没有意识到它需要与委托协议的位置相反,即将委托协议放在左边。 - barndog
谢谢你提出这个问题!那很有帮助! - Dhaval H. Nena

23

扩展 Foo where ... 只能在以下情况下使用:

  1. 泛型类或结构体:为符合某些类型约束的泛型提供默认实现。
  2. 包含一些关联类型的协议:为当关联类型符合某些类型约束时提供默认实现。
  3. 协议,其中我们为当 Self 是特定(对象/引用)类型或符合某些类型约束时提供默认实现。

例如:

// 1
class Foo<T> { }
extension Foo where T: IntegerType {}

struct Foz<T> {}
extension Foz where T: IntegerType {}

// 2
protocol Bar {
    associatedtype T
}
extension Bar where T: IntegerType {}

// 3
protocol Baz {}
extension Baz where Self: IntegerType {}

class Bax<T>: Baz {}
extension Baz where Self: Bax<Int> {
    func foo() { print("foo") }
}

let a = Bax<Int>()
a.foo() // foo

在您的情况下,UIViewController是一种非泛型类类型,不符合上述任何一种规范。
正如您在自己的答案中所写的那样,解决方案是扩展您的委托协议,并为Self: UIViewController的情况提供默认实现,而不是尝试扩展UIViewController

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接