2016-03-23 17 views
23

avere il codice seguente:trascinamento dove clausola di estensione di tipo non generico

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

in un'estensione UIViewController. Questo codice viene riutilizzato da molti viewcontroller per registrare le notifiche della tastiera. Tuttavia con Swift 2.2 produce un avvertimento. Mi piace la nuova sintassi #selector ma non sono sicuro di come implementarla in questo caso.

Penso che la soluzione corretta sia quella di creare un protocollo ed estendere UIViewController solo per le istanze conformi a tale protocollo. Il mio codice finora:

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

Tuttavia questo mi ottengo l'errore

trailing where clause for extension of non-generic type 

sulla riga di estensione. Qualche idea?

risposta

41

La soluzione era semplice da cambiare l'ordine nella clausola estensione:

extension UIViewController where Self: KeyboardNotificationDelegate 

dovrebbe essere

extension KeyboardNotificationDelegate where Self: UIViewController 
+3

Questo mi ha aiutato enormemente. Stavo facendo il contrario, 'estensione UIViewController dove Self: UICollectionViewDelegate' ma non mi ero reso conto che doveva essere capovolto con il delegato sulla sinistra. – barndog

12

extension Foo where ... può essere utilizzato solo se Foo è

  1. una classe generica o struttura: estendere con un'implementazione predefinita per i generici conformi ad alcuni tipi constrai nt,
  2. un protocollo contenente alcuni tipi associati, si estendono con un'implementazione predefinita per quando un tipo associato conforme a qualche tipo di vincolo
  3. un protocollo in cui estendiamo con un'implementazione predefinita quando Self è di uno specifico (oggetto/riferimento) digita o è conforme ad alcuni vincoli di tipo.

E.g.

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

Nel tuo caso, UIViewController è un tipo di classe non generica, che non rispondono a nessuna delle due di cui sopra.


Come hai scritto nella tua risposta, la soluzione è quella di estendere il protocollo delegato con un'implementazione di default per i casi in cui Self: UIViewController, piuttosto che tentare di estendere UIViewController.

Problemi correlati