Instantly share code, notes, and snippets.

Embed
What would you like to do?
// MARK: Protocols
protocol ResponderProtocol {
var nextResponder: ResponderProtocol? { get }
}
protocol CopyProtocol {
func copy()
}
// MARK: Concrete responder
class Responder: ResponderProtocol {
var nextResponder: ResponderProtocol?
}
// MARK: Responder chain classes
class Button: Responder {}
class View: Responder {}
class CopyableView: Responder, CopyProtocol {
func copy() {
print("Copied copyable view")
}
}
class Window: Responder, CopyProtocol {
func copy() {
print("Copied window")
}
}
// MARK: Walk responder chain helper
func walkResponderChain(firstResponder: ResponderProtocol?, handleEvent: (ResponderProtocol) -> Bool) -> ResponderProtocol? {
guard let responder = firstResponder else {
return nil
}
guard handleEvent(responder) == false else {
// Responder handled our call
return responder
}
return walkResponderChain(responder.nextResponder, handleEvent: handleEvent)
}
// MARK: Copy via responder chain
func copy(firstResponder: ResponderProtocol) -> ResponderProtocol? {
return walkResponderChain(firstResponder) { responder in
if let validResponder = responder as? CopyProtocol {
validResponder.copy()
return true
}
return false
}
}
// Test case
let button = Button()
let view = View()
let copyView = CopyableView()
let window = Window()
// Setup responder chain as Button -> CopyableView -> Window
button.nextResponder = copyView
view.nextResponder = window
copyView.nextResponder = window
copy(button)
// Setup responder chain as Button -> View -> Window
button.nextResponder = view
copy(button)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment