我正在尝试向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都会阻止这种行为,并覆盖它的代码,检查它们是否实现了协议。
答案 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
,它永远不会被改变。