Swift3 Extension on" Any?" - 班级?

时间:2017-01-13 18:57:19

标签: ios swift extension-methods

更短的解释:

您经常希望扩展" 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的第一个参数?

或者正如康纳的评论所暗示的,有没有办法:

extension  UIViewController or UIView {

而不是复制和粘贴两次?

2 个答案:

答案 0 :(得分:5)

每个结构/类都(被动地)遵守“任何”。 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 { }

这迫使你明知选择将功能添加到给定的类(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
}

答案 1 :(得分:2)

Any不是NSObject的类。它只是一个关键字,它向Swift编译器指示变量/ constant /参数可以引用任何对象或结构实例,因此无法扩展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子类中,您可以说:

self.add(Selector(("handleTap")))