从协议扩展调用select器

我正在构build简单的主题引擎,并希望有一个扩展,它将UISwipeGestureRecognizer添加到UIViewController

这是我的代码:

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

当然编译器不能find#selector(Self.switchCurrentTheme)因为它没有通过@objc指令公开。 是否有可能将此行为添加到我的扩展?

更新: Theme是一个Swift枚举,所以我不能在Themeable协议前添加@objc

我可以想出最干净的工作解决scheme,就是在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) } } 

我不确定,但你可以像访问它

  #selector(switchCurrentTheme) 

或者你可以参考这个链接来尝试访问如何在协议扩展中使用#selector(myMethodName)?

你有没有考虑创build一个包装,让你从@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) } } 

我find了解决scheme。 可能不是完美的,但它的工作原理。 由于我不能将Themeable协议定义为@objc因为它使用Swift-only enum所以我决定移动我想调用“parent”协议的方法,并将此协议定义为@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) } }