类扩展中的覆盖方法约束于swift

时间:2017-03-29 20:57:12

标签: swift uiviewcontroller protocols protocol-extension

我正在尝试向UIViewController添加默认实现触摸开始通过协议扩展符合协议的所有控制器。触摸将被发送到自定义视图,所有实现此协议的控制器都具有。

这是初始状态:

protocol WithView {
    var insideView: UIView! { get }
}

class Controller1: UIViewController, WithView {

    var insideView: UIView!

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        insideView.touchesBegan(touches, with: event)
    }

    /* Functionality of Controller 1 */
}

class Controller2: UIViewController, WithView {

    var insideView: UIView!

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        insideView.touchesBegan(touches, with: event)
    }

    /* Functionality of Controller 2 */
}

我想要完成的是所有UIViewControllers将触摸转发到insideView的情况,而不是以相同的方式为每个控制器指定。像这样:

protocol WithView {
    var insideView: UIView! { get }
}

extension UIViewController where Self: WithView {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        insideView.touchesBegan(touches, with: event)
    }
}

class Controller1: UIViewController, WithView {

    var insideView: UIView!

    /* Functionality of Controller 1 */
}

class Controller2: UIViewController, WithView {

    var insideView: UIView!

    /* Functionality of Controller 2 */
}

但这不编译,说'Trailing where子句扩展非泛型类型UIViewController'

我试图以相反的方式定义它,如下:

extension WithView where Self: UIViewController {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        insideView.touchesBegan(touches, with: event)
    }
}

虽然扩展格式正确,但编译器会抱怨,因为它无法“覆盖”协议扩展中的内容。

我想要的是一个约束于协议的类扩展,例如我可以覆盖这些方法,而不是强制在实现此协议的所有控制器中复制粘贴代码。

编辑:根据建议的解决方案

我也提出了这个解决方案:

protocol WithView {
    var insideView: UIView! { get }
}

extension UIViewController {
    override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let viewSelf = (self as? WithView) else {
            super.touchesBegan(touches, with: event)
            return
        }
        viewSelf.insideView.touchesBegan(touches, with: event)
    }
}

class Controller1: UIViewController, WithView {

    var insideView: UIView!

    /* Functionality of Controller 1 */
}

class Controller2: UIViewController, WithView {

    var insideView: UIView!

    /* Functionality of Controller 2 */
}

它做我想要的,但感觉有点乱,因为那时所有的UIViewControllers都会阻止这种行为,并覆盖它的代码,检查它们是否实现了协议。

2 个答案:

答案 0 :(得分:2)

您可以为所有视图控制器定义自己的超类,并检查self是否符合特定协议(在您的情况下为WithView),以决定是否应将触摸事件转发到任何其他视图。< / p>

class MyViewController: UIViewController {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let selfWithView = self as? WithView {
            selfWithView.insideView.touchesBegan(touches, with: event)
        } else {
            super.touchesBegan(touches, with: event)
        }
    }
}

这是一种更灵活的方法,您不必在每个视图控制器子类中存储insideView属性。

答案 1 :(得分:1)

您可以通过创建一个类并从中进行子类化来完成此操作:

class WithViewController: UIViewController, WithView {

    var insideView: UIView!

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        insideView.touchesBegan(touches, with: event)
    }
}

class ViewController: WithViewController {

}

唯一的缺点是你必须有一个默认的insideView,它永远不会被改变。