2016-04-14 14 views
8

Ich baue einfaches Thema Motor und möchte eine Erweiterung haben, die hier UISwipeGestureRecognizer-UIViewControllerAufruf Wähler von Protokollerweiterung

fügt ist mein Code:

protocol Themeable { 
    func themeDidUpdate(currentTheme: Theme) -> Void 
} 

extension Themeable where Self: UIViewController { 
    func switchCurrentTheme() { 
     Theme.switchTheme() 
     themeDidUpdate(Theme.currentTheme) 
    } 

    func addSwitchThemeGestureRecognizer() { 
     let gestureRecognizer = UISwipeGestureRecognizer(target: self, action:#selector(Self.switchCurrentTheme)) 
     gestureRecognizer.direction = .Down 
     gestureRecognizer.numberOfTouchesRequired = 2 
     self.view.addGestureRecognizer(gestureRecognizer) 
    } 
} 

Natürlich Compiler nicht #selector(Self.switchCurrentTheme) finden wie es nicht über @objc Direktive ausgesetzt ist. Ist es möglich, dieses Verhalten meiner Erweiterung hinzuzufügen?

UPDATE:Theme ist ein Swift-Enumeration, also kann ich nicht @objc vor Themeable Protokoll hinzufügen

Antwort

0

Ich bin nicht sicher, aber Sie können darauf zugreifen wie

#selector(switchCurrentTheme) 

oder Sie kann diesen Link zu versuchen Besuchen Sie How to use #selector(myMethodName) in a protocol extension?

+0

@OgreSwamp ist es für Sie gearbeitet? –

+1

Ihre Lösung funktioniert nicht. Lösung auf dem von Ihnen angegebenen Link funktioniert auch nicht für mich. Es beschreibt eine sehr spezifische Situation - warten vor Methodenaufruf. Ja, Sie können vermeiden, objc target/action pattern dort zu verwenden, aber es gibt keine andere Möglichkeit, gestikulierte Listener hinzuzufügen, soweit ich weiß. – OgreSwamp

0

Ich habe eine Lösung gefunden. Mag nicht der perfekte sein, aber es funktioniert. Da ich kein Themeable Protokoll als @objc definieren kann, weil es nur Swift-enum verwendet, entschied ich mich, Methode zu verschieben, die ich zum "Eltern" -Protokoll aufrufen und dieses Protokoll als @objc definieren möchte. Es scheint, wie es funktioniert, aber ich weiß nicht wirklich, wie es um ehrlich zu sein ...

@objc protocol ThemeSwitcher { 
    func switchCurrentTheme() 
} 

protocol Themeable: ThemeSwitcher { 
    func themeDidUpdate(currentTheme: Theme) -> Void 
} 

extension Themeable where Self: UIViewController { 
    func switchCurrentTheme() { 
     Theme.switchTheme() 
     themeDidUpdate(Theme.currentTheme) 
    } 

    func addSwitchThemeGestureRecognizer() { 
     let gestureRecognizer = UISwipeGestureRecognizer(target: self, action:#selector(switchCurrentTheme)) 
     gestureRecognizer.direction = .Down 
     gestureRecognizer.numberOfTouchesRequired = 2 
     self.view.addGestureRecognizer(gestureRecognizer) 
    } 
} 
+1

funktioniert immer noch nicht, da ich '@ objc' nicht auf meinen' ViewController' anwenden kann, der '' Themeable' 'Protokoll implementiert. – OgreSwamp

0

Haben Sie darüber nachgedacht einen Wrapper Erstellen Sie Ihre [email protected] objc Funktion von einem @objc man anrufen lassen?

@objc class Wrapper: NSObject { 
    let themeable: Themeable 

    init(themeable: Themeable) { 
     self.themeable = themeable 
    } 

    func switchCurrentTheme() { 
     Theme.switchTheme() 
     themeable.themeDidUpdate(Theme.currentTheme) 
    } 
} 

protocol Themeable { 
    func themeDidUpdate(currentTheme: Theme) -> Void 
} 

extension Themeable where Self: UIViewController { 
    func addSwitchThemeGestureRecognizer() { 
     let wrapper = Wrapper(themeable: self) 
     let gestureRecognizer = UISwipeGestureRecognizer(target: wrapper, action:#selector(Wrapper.switchCurrentTheme)) 
     gestureRecognizer.direction = .Down 
     gestureRecognizer.numberOfTouchesRequired = 2 
     self.view.addGestureRecognizer(gestureRecognizer) 
    } 
} 
+0

Dies ist eine großartige Idee, aber es konnte nicht funktionieren. :( –

11

Die sauberste, Arbeits Lösung, die ich oben kommen könnte mit einer privaten Erweiterung auf UIViewController mit dem Verfahren in Frage zu definieren war. Durch die Begrenzung des Anwendungsbereichs auf private, den Zugang zu dieser Methode wird isoliert innerhalb der Quelldatei, in der das Protokoll in definiert ist hier, wie es aussieht.

protocol Themeable { 
    func themeDidUpdate(currentTheme: Theme) -> Void 
} 

private extension UIViewController { 
    @objc func switchCurrentTheme() { 
     guard let themeableSelf = self as? Themeable else { 
      return 
     } 

     Theme.switchTheme() 
     themeableSelf.themeDidUpdate(Theme.currentTheme) 
    } 
} 

extension Themeable where Self: UIViewController { 
    func addSwitchThemeGestureRecognizer() { 
     let gestureRecognizer = UISwipeGestureRecognizer(target: self, action:#selector(switchCurrentTheme)) 
     gestureRecognizer.direction = .Down 
     gestureRecognizer.numberOfTouchesRequired = 2 
     self.view.addGestureRecognizer(gestureRecognizer) 
    } 
} 
+1

Danke dafür! Arbeitete wie ein Charme. :) In Swift 3 muss die private Erweiterung von UIViewController jetzt fileprivate sein. Außerdem sollte die Funktion switchCurrentTheme fileprivate statt intern sein. –