从协议扩展中调用选择器 [英] Calling selector from protocol extension

查看:124
本文介绍了从协议扩展中调用选择器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm building simple theme engine and would like have an extension which adds UISwipeGestureRecognizer to 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)
    }
}

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

Of course compiler can't find #selector(Self.switchCurrentTheme) as it isn't exposed via @objc directive. Is it possible to add this behaviour to my extension?

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

UPDATE: Theme is a Swift enum, so I can't add @objc in front of Themeable protocol

推荐答案

我能想到的最干净,可行的解决方案是使用所讨论的方法在UIViewController上定义一个私有扩展.通过将范围限制为private,可以仅在定义协议的源文件中访问此方法.其外观如下:

The cleanest, working solution I could come up with was to define a private extension on UIViewController with the method in question. By limiting the scope to private, access to this method is isolated to within the source file where the protocol is defined in. Here's what it looks like:

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

这篇关于从协议扩展中调用选择器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆