【问题标题】:Swift3 Extension on "Any?" -ish class?“任何?”上的 Swift3 扩展-ish 类?
【发布时间】:2017-01-13 18:57:18
【问题描述】:

简短的解释:

您经常希望在“目标”上进行扩展……而目标通常是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 {

而不是复制粘贴两次?

【问题讨论】:

  • 这是非常迂回的。任何只调用其参数函数 (addGestureRecognizer) 的函数都可以附加到任何扩展上。您希望能够从控制器或视图以外的任何地方添加手势识别器这一事实并不是一个好的设计决策。
  • 嗨@ConnorNeville - 当然,正如您所说的控制器或视图。所以,目前我需要有两个扩展——一个用于控制器,一个用于视图。那么,如何概括呢?只有一个分机?
  • 这是一个非常简单的想法,您可能希望在“目标”上进行扩展......目标通常是Any?。怎么做?
  • 整个概念似乎有点笨拙......那么,为什么你首先需要做这么复杂的事情呢?我的意思是,您希望通过让生活变得更艰难来消除或解决的更大问题是什么?
  • @holex,每一个扩展都是“无用的”——你可以通过写出每一个扩展来消除它。 Swift 的本质是它就是 Swift——你可以“重写”该语言,让它更快。

标签: ios swift extension-methods


【解决方案1】:

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

【讨论】:

  • 全面思考!
【解决方案2】:

Any 不像 NSObject 那样是一个类。它只是一个关键字,向 Swift 编译器表明变量/常量/参数可以引用任何对象或结构实例,因此无法扩展 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")))

【讨论】:

  • ( "虽然,对于 UIView 扩展,您不需要 v,因为这将是 self;在其他一些 UIView 上安装手势识别器没有意义" ...子视图很常见。)
  • 所以,将它添加到子视图中。我的观点是,它是操作的目标,而不是您添加需要提供的手势识别器的视图
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多