2016-04-14 125 views
8

我建立簡單的主題引擎,並希望有一個擴展,它增加了UISwipeGestureRecognizerUIViewController從協議擴展調用選擇

這裏是我的代碼:

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

當然編譯器無法找到#selector(Self.switchCurrentTheme)因爲它沒有通過@objc指令公開。是否有可能將此行爲添加到我的擴展?

UPDATE:Theme是斯威夫特枚舉,所以我不能在前面加@objcThemeable協議

回答

0

我不知道,但你可以像

#selector(switchCurrentTheme) 

,或者你訪問它可以參考此鏈接試試 參觀How to use #selector(myMethodName) in a protocol extension?

+0

@OgreSwamp是它爲你工作? –

+1

您的解決方案不起作用。您提供的鏈接解決方案也不適用於我。它描述了非常具體的情況 - 在方法調用之前等待。是的,你可以避免在那裏使用objc目標/動作模式,但據我所知沒有其他方式來添加手勢監聽器。 – OgreSwamp

0

我找到了解決方案。可能不是完美的,但它的工作原理。 由於我不能將Themeable協議定義爲@objc,因爲它使用Swift-only enum我決定移動要調用「父」協議的方法並將此協議定義爲@objc。這似乎是它的工作原理,但我真的不喜歡它,說實話......

@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

仍然無法正常工作,因爲我無法將'@ objc'應用於實現'Themeable'協議的'ViewController' .. – OgreSwamp

0

你有沒有考慮建立一個包裝,讓你從一個@objc打電話給你的非@ objc功能?

@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

這是一個好主意,但無法讓它工作。 :( –

11

最乾淨,工作解決方案,我能想出是確定與問題的方法上UIViewController私有擴展。通過限制範圍private,訪問這個方法在協議中定義的源文件中分離到這裏是什麼樣子:

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

感謝你!工作就像一個魅力:)在Swift 3中,UIViewController的私有擴展現在需要是fileprivate。另外,switchCurrentTheme函數應該是fileprivate而不是內部。 –