UIResponder chain produces two extra responders

275 Views Asked by At

I'm running Xcode 14.0 beta 4. I have just one ViewController with a root view in storyboard. I want to see an entire Responder Chain from UIView to AppDelegate. To do this, I created extensions:

enter image description here

import UIKit

extension AppDelegate {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("APPLICATION")
        next?.touchesBegan(touches, with: event)
    }
} 
extension UIView {
    public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("View")
        next?.touchesBegan(touches, with: event)
    }
}
extension UIWindow {
    public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("Window")
        next?.touchesBegan(touches, with: event)
    }
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .systemGreen
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("CONTROLLER")
        next?.touchesBegan(touches, with: event)
    }
}

Console gives me out the following sequence:

enter image description here

Question:

Where do these two extra responders come from?

2

There are 2 best solutions below

0
Inder Kumar Rathore On BEST ANSWER

These are UITransitionView and UIDropShadowView

you can either debug view hierarchy or print self to know it. There is one post on SO about it : UITransitionView and UILayoutContainerView, I don't have much knowledge about it nor did I find any apple docs about it. They might be internal APIs

extension UIView {
    public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("View \(self)")
        next?.touchesBegan(touches, with: event)
    }
}

enter image description here

0
Andy Jazz On

I also found a way to find out what these two responders are:

class ViewController: UIViewController {

    private func responderChain(_ responder: UIResponder?) {
        if let responder {
            print(responder)
            responderChain(responder.next)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .systemGreen

        DispatchQueue.main.async {
            self.responderChain(self)
        }
    }
}

enter image description here