
Qual é a diferença entre o primeiro e o segundo exemplo?
Qual é o alvo responsável?
Nesse caso, o método é chamado quando o botão é clicado?
TL; DR
Quando um botão é clicado, nosso método é chamado nos dois casos.
Somente no primeiro exemplo, o UIKit tentará chamar o método no destino atribuído (temos o ViewController ). Ele falhará se esse método não existir.
No segundo exemplo, a cadeia de resposta do iOS é usada, o UIKit procurará o UIResponder mais próximo -a, que possui esse método. Não haverá falha se o nosso método não for encontrado.
UIViewController, UIView, UIApplication herdam do UIResponder .
Cadeia de resposta do iOS e o que há por trás
UIKit processo da cadeia de resposta do iOS é tratado pelo UIKit , que trabalha dinamicamente com uma lista vinculada de UIResponder . Essa lista do UIKit criada a partir do primeiro respondedor (o primeiro UIResponder que registrou o evento, temos o UIButton(UIView) e suas subviews .

O UIKit percorre a lista de UIResponder e verifica com canPerformAction a nossa função.
 open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool 
Se o UIResponder selecionado não puder trabalhar com um método específico,
UIKit envia recursivamente ações para o próximo UIResponder na lista usando o método de target que retorna o próximo UIResponder .
 open func target(forAction action: Selector, withSender sender: Any?) -> Any? 
Esse processo é repetido até que um dos UIResponder possa trabalhar com nosso método ou a lista termine e o sistema ignore esse evento.
No exemplo do segundo clique, ele foi tratado pelo UIViewController , mas o UIKit primeiro enviou uma solicitação ao UIView pois era o primeiro respondedor. Ele não tinha o método necessário; portanto, o UIKit redirecionou as ações para o próximo UIResponder em uma lista vinculada, que era o UIViewController que possuía o método desejado.
Na maioria dos casos, a iOS Responder Chain do iOS Responder Chain é uma simples lista subviews de subviews , mas sua ordem pode ser alterada. Você pode fazer o UIResponder (becomeFirstResponder) se tornar
primeiro UIResponder e retorne à posição antiga usando resignFirstResponder . Isso geralmente é usado com um UITextField para mostrar o teclado que será chamado apenas quando o UITextField for o first responder .
Cadeia de resposta do iOS e UIEvent
A Cadeia de Respondentes também está envolvida em tocar na tela, movimentos, cliques. Quando o sistema detecta algum tipo de evento (toque, movimento, controle remoto, imprensa), um UIEvent é criado sob o capô e enviado usando o método UIApplication.shared.sendEvent() para o UIWindow . Após receber o evento, o UIWindow determina o uso do hitTest:withEvent ao qual esse evento pertence ao UIResponder e atribui a ele o first responder . A seguir, é apresentado o trabalho com uma lista vinculada de UIResponder descrita acima.
Para trabalhar com UIEvent sistema, as subclasses de UIResponder (UIViewController, UIView, UIApplication) podem substituir esses métodos:
 open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) open func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) open func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) open func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) open func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) open func pressesChanged(_ presses: Set<UIPress>, with event: UIPressesEvent?) open func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) open func pressesCancelled(_ presses: Set<UIPress>, with event: UIPressesEvent?) open func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) open func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) open func motionCancelled(_ motion: UIEvent.EventSubtype, with event: UIEvent?) open func remoteControlReceived(with event: UIEvent?) 
Apesar do fato de a capacidade de herdar e chamar sendEvent manualmente estar presente, o UIResponder não se destina a isso. Isso pode criar muitos problemas com a operação de eventos personalizados, o que pode levar a ações incompreensíveis causadas por um first responeder respondente aleatório que pode responder ao seu evento.
Por que é útil, onde usar
Apesar do iOS Responder Chain totalmente controlado pelo UIKit , ele pode ser usado para resolver o problema de delegação / comunicação. UIResponder ações do UIResponder são semelhantes ao NotificationCenter.default.post único.
Vamos dar um exemplo: temos um UIViewController , que está no fundo da pilha UINavigationController e precisamos contar o que aconteceu quando um botão foi clicado em outra tela. Você pode usar o padrão delagate ou NotificationCenter.default.post , mas uma opção bastante simples é usar a iOS Responder Chain do iOS Responder Chain .
 button.addTarget(nil, action: #selector(RootVC.doSomething), for: .touchUpInside) 
Quando pressionado, o método na UIViewController será chamado. #selector pode usar os seguintes parâmetros:
 @objc func doSomething() @objc func doSomething(sender: Any?) @objc func doSomething(sender: Any?, event: UIEvent?) 
remetente é o objeto que enviou o evento - UIButton, UITextField e assim por diante.
Recursos adicionais para aprendizado [eng]:
Boa descrição do UIEvent, UIResponder e alguns exemplos avançados (coordenador patern)
Leia mais sobre a cadeia de resposta do ios
Exemplo de cadeia de respondentes na prática
Off dock na cadeia de resposta do iOS
Off Dock por UIResponder