2016-04-14 22 views
8

buduję Prosty system rozrywki i chciałby mieć rozszerzenie, które dodaje UISwipeGestureRecognizer do UIViewControllerWywołanie selektor z rozszerzeniem protokołu

Oto mój kod:

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

oczywiście kompilator nie może znaleźć #selector(Self.switchCurrentTheme) ponieważ nie jest udostępniony poprzez dyrektywę @objc. Czy jest możliwe dodanie tego zachowania do mojego rozszerzenia?

UPDATE:Theme jest Swift enum, więc nie mogę dodać @objc przed protokołu Themeable

Odpowiedz

0

Nie jestem pewien, ale można go jak

#selector(switchCurrentTheme) 

lub ciebie może polecić ten link, aby wypróbować Odwiedź How to use #selector(myMethodName) in a protocol extension?

+0

@OgreSwamp jest to pracował dla Ciebie? –

+1

Twoje rozwiązanie nie działa. Rozwiązanie podanego linku również nie działa dla mnie. Opisuje bardzo specyficzną sytuację - oczekiwanie przed wywołaniem metody. Tak, można uniknąć użycia celu docelowego/akcji objektu, ale nie ma innego sposobu na dodanie gestem słuchacza, o ile wiem. – OgreSwamp

0

Znalazłem rozwiązanie. Może nie jest idealny, ale działa. Ponieważ nie mogę zdefiniować protokołu Themeable jako @objc, ponieważ używa on tylko Swift enum Postanowiłem przenieść metodę, którą chcę wywołać, do protokołu "rodzica" i zdefiniować ten protokół jako @objc. Wydaje się, że to działa, ale ja nie lubię tego, aby być uczciwym ...

@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

nadal nie działa, ponieważ nie mogę zastosować '@ objc' do mojego' ViewController' który implementuje protokół 'Themeable' .. – OgreSwamp

0

Czy za stworzenie opakowania aby zadzwonić do nieprzestrzegania funkcję @ objc z @objc jednego?

@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

To świetny pomysł, ale nie mógł go uruchomić. :( –

11

najczystszy, roztwór roboczy mogłem wymyślić było określenie prywatną rozszerzenie na UIViewController z metodą mowa. Ograniczając zakres do private, dostęp do tej metody jest odizolowany w pliku źródłowym, gdzie protokół jest zdefiniowany w Oto jak to wygląda.

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

Dzięki za to! Pracowałem jak urok. :) W Swift 3, prywatne rozszerzenie UIViewController musi teraz być zamiast tego fileprivate. Ponadto funkcja switchCurrentTheme powinna mieć wartość alfanumeryczną, a nie wewnętrzną. –

Powiązane problemy