1

我正在尝试将默认实现添加到 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 */
}

但这不会编译,说'尾随非泛型 UIViewController 扩展的 where 子句'

我试图以另一种方式定义它,如下所示:

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 都会继承这种行为,并会覆盖它的代码,检查它们是否实现了协议。

4

2 回答 2

2

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

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在每个视图控制器子类中存储属性。

于 2017-03-29T21:40:45.097 回答
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,它永远不会改变。

于 2017-03-29T21:33:34.807 回答