// 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