web-dev-qa-db-fra.com

Clause Where de fin pour l'extension de type non générique

J'ai le code suivant:

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

dans une extension à UIViewController. Ce code est réutilisé par de nombreux viewcontroller pour s'inscrire aux notifications du clavier. Cependant avec Swift 2.2 il produit un avertissement. J'aime le nouveau #selector syntaxe mais ne savez pas comment l'implémenter dans ce cas.

Je pense que la bonne solution est de créer un protocole et d'étendre UIViewController uniquement pour les instances conformes à ce protocole. Mon code jusqu'à présent:

@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(_:)))
        }
    }
}

Mais cela me fait l'erreur

trailing where clause for extension of non-generic type

sur la ligne d'extension. Des idées?

35
Sunkas

La solution était simple de changer l'ordre dans la clause d'extension:

extension UIViewController where Self: KeyboardNotificationDelegate

devrait être

extension KeyboardNotificationDelegate where Self: UIViewController
67
Sunkas

extension Foo where ... ne peut être utilisé que si Foo est

  1. une classe ou structure générique: étendre avec une implémentation par défaut pour des génériques conformes à une contrainte de type,
  2. un protocole contenant certains types associés, étendre avec une implémentation par défaut pour quand un type associé se conforme à une contrainte de type
  3. un protocole où nous étendons avec une implémentation par défaut pour quand Self est d'un type spécifique (objet/référence), ou conforme à une contrainte de type.

Par exemple.

// 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

Dans votre cas, UIViewController est un type de classe non générique, qui n'est conforme à aucun des deux ci-dessus.


Comme vous l'avez écrit dans votre propre réponse, la solution consiste à étendre votre protocole délégué avec une implémentation par défaut pour les cas où Self: UIViewController, plutôt que d'essayer d'étendre UIViewController.

19
dfri