从协议扩展调用选择器

Ogr*_*amp 8 ios swift swift2 protocol-extension

我建立简单的主题引擎,并希望有一个扩展,它增加了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)
    }
}
Run Code Online (Sandbox Code Playgroud)

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

UPDATE: Theme是一个Swift枚举,所以我不能@objcThemeable协议前添加

Dan*_*erz 15

我能想到的最干净,最有效的解决方案是UIViewController使用相关方法定义私有扩展.通过限制范围private,对此方法的访问被隔离到定义协议的源文件中.这是它的样子:

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

fileprivate 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)
    }
}
Run Code Online (Sandbox Code Playgroud)


Ogr*_*amp 1

我找到了解决方案。可能不是完美的,但它确实有效。由于我无法定义Themeable协议,因为@objc它仅使用 Swift,所以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)
    }
}
Run Code Online (Sandbox Code Playgroud)