UIResponder chain, Swift style

Yes, I do something similar. But since mine is for AppKit, it's somewhat more complicated. To mimic NSApplication's target search strategy, I have to look at several objects not in the responder chain, and I have to search multiple possible responder chains in succession.

extension NSResponder {
    public func nearestResponder<Target>(ofType type: Target.Type) -> Target? {
        var app: NSApplication? = NSApplication.shared
        var keyWindow = app!.keyWindow
        var keyWindowController = keyWindow?.windowController
        var mainWindow = app!.mainWindow
        var mainWindowController = mainWindow?.windowController
        if mainWindow === keyWindow { mainWindow = nil }
        var next: NSResponder? = self

        while let candidate = next {
            if let match = candidate as? Target {
                return match
            }

            if candidate === keyWindow {
                if let match = keyWindow?.delegate as? Target { return match }
                keyWindow = nil
            }

            if candidate === keyWindowController {
                if let match = keyWindowController?.document as? Target { return match }
                keyWindowController = nil
            }

            if candidate === mainWindow {
                if let match = mainWindow?.delegate as? Target { return match }
                mainWindow = nil
            }

            if candidate === mainWindowController {
                if let match = mainWindowController?.document as? Target { return match }
                mainWindowController = nil
            }

            if candidate === app {
                if let match = app?.delegate as? Target { return match }
                if let match = NSDocumentController.shared as? Target { return match }
                app = nil
            }

            next = candidate.nextResponder ?? keyWindow.firstResponder ?? mainWindow.firstResponder ?? app
        }

        return nil
    }
}
1 Like