I am trying to add default implementations to UIViewController touches began to all controllers conforming to a protocol through a protocol extension. There the touch would be sent to a custom view all controllers implementing this protocol have.
Here's the initial state:
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 */
}
What I'd like to accomplish is a situation where all the UIViewControllers forwarded the touches to the insideView without specifying so for every controller the same way. Something like this:
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 */
}
But this does not compile, saying 'Trailing where clause for extension of non-generic type UIViewController'
I tried to define it the other way around, like so:
extension WithView where Self: UIViewController {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
insideView.touchesBegan(touches, with: event)
}
}
and while the extension is properly formatted, the compiler complains, as it cannot 'override' things in a protocol extension.
What I'd like is a class extension constrained to a protocol, such as I can override this methods and not being forced to copy-paste code inside all my controllers implementing this protocol.
Edit: as per proposed solutions
I also came up with this solution:
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 */
}
It does what I want, but it feels a bit messy though, because then all the UIViewControllers would intherit this behavior, and would override its code, checking if they implement the protocol.