"Any?" -ish class 上的 Swift3 扩展?
Swift3 Extension on "Any?" -ish class?
更简短的解释:
您经常希望在 "target" 上扩展...而目标通常是 Any?
。但是您不能在 Any
上进行扩展。怎么做?
考虑一下,
extension UIViewController {
func add(tap v:UIView, _ action:Selector) {
let t = UITapGestureRecognizer(target: self, action: action)
v.addGestureRecognizer(t)
}
}
太好了,你现在可以...
self.tap(redButton, #selector(clickedRedButton))
...在任何视图控制器中。
但是您几乎可以对任何目标执行相同的操作。
因此,要在 UITableViewCell 上使用扩展,您还必须拥有....
extension UIGestureRecognizerDelegate {
func add(tap v:UIView, _ action:Selector) {
let t = UITapGestureRecognizer(target: self, action: action)
v.addGestureRecognizer(t)
}
}
UITapGestureRecognizer 的目标参数实际上是Any?
但是,你不能这样做...
extension Any {
有什么解决办法?如何制作可在 Any?
上运行的扩展,例如 UITapGestureRecognizer
的第一个参数?
或者如 Conner 的评论所暗示的那样,有没有办法:
extension UIViewController or UIView {
而不是复制粘贴两次?
"Any" 被每个 struct/class 遵守(被动)。 Any 的扩展会将该功能添加到语言和代码中的每个类型。目前这是不可能的,我怀疑它是否会(或应该)。
无论如何,这里有几种方法可以解决这个问题。
我的偏好是添加以下功能的协议扩展:
protocol TapGestureAddable {
func addTapGestureRecognizer(to view: UIView, with action: Selector) -> UITapGestureRecognizer
}
extension TapGestureAddable {
func addTapGestureRecognizer(to view: UIView, with action: Selector) -> UITapGestureRecognizer {
let recognizer = UITapGestureRecognizer(target: self, action: action)
view.addGestureRecognizer(recognizer)
return recognizer
}
}
extension UIViewController: TapGestureAddable { }
extension UIView: TapGestureAddable { }
这迫使您有意识地选择 将功能添加到给定的 class(IMO 的好事),而不必复制任何有意义的代码。
可能更好的选择是将此逻辑改为 UIView 的扩展:
extension UIView {
func addTapGestureRecognizer(with responder: Any, for action: Selector) -> UITapGestureRecognizer {
let recognizer = UITapGestureRecognizer(target: responder, action: action)
self.addGestureRecognizer(recognizer)
return recognizer
}
func addTapGestureRecognizer(with action: Selector) -> UITapGestureRecognizer {
let recognizer = UITapGestureRecognizer(target: self, action: action)
self.addGestureRecognizer(recognizer)
return recognizer
}
}
否则,只做一个全局函数:
func addTapGestureRecognizer(to view: UIView, with responder: Any, for action: Selector) -> UITapGestureRecognizer {
let recognizer = UITapGestureRecognizer(target: responder, action: action)
view.addGestureRecognizer(recognizer)
return recognizer
}
Any
不像 NSObject
那样是 class。它只是一个关键字,向 Swift 编译器指示 variable/constant/parameter 可以引用任何对象或结构实例,因此无法扩展 Any
.
如果您考虑您要尝试做的事情,无论如何您的两个扩展之间会有细微差别;
UIViewController
扩展需要接受目标视图(您的 v
)参数
- 而对于
UIView
扩展,您不需要 v
,因为这将是 self
;在其他 UIView
. 上安装手势识别器没有意义
- 对于
UIView
扩展,您可能需要为选择器指定不同的目标。
- 您没有向 UIViewController 添加手势识别器,因此从语义上讲,它不会以这种方式扩展
UIViewController
。
所以,对我来说,逻辑扩展看起来像这样:
extension UIView {
func add(_ action:Selector,tapHandler target:Any = self) {
let t = UITapGestureRecognizer(target: target, action: action)
self.addGestureRecognizer(t)
}
}
现在,在 UIViewController
中你可以这样说:
self.redButton.add(Selector(("handleTap")), tapHandler: self)
在 UIView
subclass 中你可以说:
self.add(Selector(("handleTap")))
更简短的解释:
您经常希望在 "target" 上扩展...而目标通常是 Any?
。但是您不能在 Any
上进行扩展。怎么做?
考虑一下,
extension UIViewController {
func add(tap v:UIView, _ action:Selector) {
let t = UITapGestureRecognizer(target: self, action: action)
v.addGestureRecognizer(t)
}
}
太好了,你现在可以...
self.tap(redButton, #selector(clickedRedButton))
...在任何视图控制器中。
但是您几乎可以对任何目标执行相同的操作。
因此,要在 UITableViewCell 上使用扩展,您还必须拥有....
extension UIGestureRecognizerDelegate {
func add(tap v:UIView, _ action:Selector) {
let t = UITapGestureRecognizer(target: self, action: action)
v.addGestureRecognizer(t)
}
}
UITapGestureRecognizer 的目标参数实际上是Any?
但是,你不能这样做...
extension Any {
有什么解决办法?如何制作可在 Any?
上运行的扩展,例如 UITapGestureRecognizer
的第一个参数?
或者如 Conner 的评论所暗示的那样,有没有办法:
extension UIViewController or UIView {
而不是复制粘贴两次?
"Any" 被每个 struct/class 遵守(被动)。 Any 的扩展会将该功能添加到语言和代码中的每个类型。目前这是不可能的,我怀疑它是否会(或应该)。
无论如何,这里有几种方法可以解决这个问题。
我的偏好是添加以下功能的协议扩展:
protocol TapGestureAddable {
func addTapGestureRecognizer(to view: UIView, with action: Selector) -> UITapGestureRecognizer
}
extension TapGestureAddable {
func addTapGestureRecognizer(to view: UIView, with action: Selector) -> UITapGestureRecognizer {
let recognizer = UITapGestureRecognizer(target: self, action: action)
view.addGestureRecognizer(recognizer)
return recognizer
}
}
extension UIViewController: TapGestureAddable { }
extension UIView: TapGestureAddable { }
这迫使您有意识地选择 将功能添加到给定的 class(IMO 的好事),而不必复制任何有意义的代码。
可能更好的选择是将此逻辑改为 UIView 的扩展:
extension UIView {
func addTapGestureRecognizer(with responder: Any, for action: Selector) -> UITapGestureRecognizer {
let recognizer = UITapGestureRecognizer(target: responder, action: action)
self.addGestureRecognizer(recognizer)
return recognizer
}
func addTapGestureRecognizer(with action: Selector) -> UITapGestureRecognizer {
let recognizer = UITapGestureRecognizer(target: self, action: action)
self.addGestureRecognizer(recognizer)
return recognizer
}
}
否则,只做一个全局函数:
func addTapGestureRecognizer(to view: UIView, with responder: Any, for action: Selector) -> UITapGestureRecognizer {
let recognizer = UITapGestureRecognizer(target: responder, action: action)
view.addGestureRecognizer(recognizer)
return recognizer
}
Any
不像 NSObject
那样是 class。它只是一个关键字,向 Swift 编译器指示 variable/constant/parameter 可以引用任何对象或结构实例,因此无法扩展 Any
.
如果您考虑您要尝试做的事情,无论如何您的两个扩展之间会有细微差别;
UIViewController
扩展需要接受目标视图(您的v
)参数- 而对于
UIView
扩展,您不需要v
,因为这将是self
;在其他UIView
. 上安装手势识别器没有意义
- 对于
UIView
扩展,您可能需要为选择器指定不同的目标。 - 您没有向 UIViewController 添加手势识别器,因此从语义上讲,它不会以这种方式扩展
UIViewController
。
所以,对我来说,逻辑扩展看起来像这样:
extension UIView {
func add(_ action:Selector,tapHandler target:Any = self) {
let t = UITapGestureRecognizer(target: target, action: action)
self.addGestureRecognizer(t)
}
}
现在,在 UIViewController
中你可以这样说:
self.redButton.add(Selector(("handleTap")), tapHandler: self)
在 UIView
subclass 中你可以说:
self.add(Selector(("handleTap")))