从协议扩展调用选择
我建立简单的主题引擎,并希望有一个扩展,它增加了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)
}
}
当然编译器无法找到#selector(Self.switchCurrentTheme)
因为它没有通过@objc
指令公开。是否有可能将此行为添加到我的扩展?
UPDATE:Theme
是斯威夫特枚举,所以我不能在前面加@objc
Themeable
协议
我不知道,但你可以像
#selector(switchCurrentTheme)
,或者你访问它可以参考此链接试试 参观How to use #selector(myMethodName) in a protocol extension?
我找到了解决方案。可能不是完美的,但它的工作原理。 由于我不能将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)
}
}
仍然无法正常工作,因为我无法将'@ objc'应用于实现'Themeable'协议的'ViewController' .. – OgreSwamp
你有没有考虑建立一个包装,让你从一个@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)
}
}
这是一个好主意,但无法让它工作。 :( –
最干净,工作解决方案,我能想出是确定与问题的方法上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)
}
}
感谢你!工作就像一个魅力:)在Swift 3中,UIViewController的私有扩展现在需要是fileprivate。另外,switchCurrentTheme函数应该是fileprivate而不是内部。 –
@OgreSwamp是它为你工作? –
您的解决方案不起作用。您提供的链接解决方案也不适用于我。它描述了非常具体的情况 - 在方法调用之前等待。是的,你可以避免在那里使用objc目标/动作模式,但据我所知没有其他方式来添加手势监听器。 – OgreSwamp