
¿Cuál es la diferencia entre el primer y el segundo ejemplo?
¿De qué es el objetivo responsable?
¿En qué caso se llama al método cuando se hace clic en el botón?
TL; DR
Cuando se hace clic en un botón, se llama a nuestro método en ambos casos.
Solo en el primer ejemplo, UIKit intentará llamar al método en el objetivo asignado (tenemos ViewController
). Se bloqueará si este método no existe.
En el segundo ejemplo, se usa la cadena de UIKit
iOS, UIKit
buscará el UIResponder
más UIResponder
, que tiene este método. No habrá bloqueo si no se encuentra nuestro método.
UIViewController, UIView, UIApplication
heredan de UIResponder
.
iOS Responder Chain y lo que hay debajo del capó
UIKit
maneja UIKit
proceso de la cadena de UIKit
de UIKit
, que funciona dinámicamente con una lista vinculada de UIResponder
. Esta lista UIKit
crea a partir del primer respondedor (el primer UIResponder
que registró el evento, tenemos UIButton(UIView)
y sus subviews
.

UIKit revisa la lista de UIResponder
y verifica con canPerformAction
para nuestra función.
open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool
Si el UIResponder
seleccionado no puede funcionar con un método específico,
UIKit
envía acciones recursivamente al siguiente UIResponder
de la lista utilizando el método de target
que devuelve el siguiente UIResponder
.
open func target(forAction action: Selector, withSender sender: Any?) -> Any?
Este proceso se repite hasta que uno de los UIResponder
pueda trabajar con nuestro método o la lista finalice y el sistema ignore este evento.
En el segundo ejemplo de clic, el UIViewController
lo UIViewController
, pero UIKit
primero envió una solicitud al UIView
ya que fue el primer respondedor. No tenía el método requerido, por lo que UIKit
redirigió las acciones al siguiente UIResponder
en una lista vinculada que era el UIViewController
que tenía el método deseado.
En la mayoría de los casos, la iOS Responder Chain
de subviews
de iOS Responder Chain
es una simple lista subviews
de subviews
, pero su orden se puede cambiar. Puede hacer que UIResponder (becomeFirstResponder)
convertirse en UIResponder (becomeFirstResponder)
convierta
primer UIResponder
y devolverlo a la posición anterior usando resignFirstResponder
. Esto a menudo se usa con un UITextField
para mostrar el teclado que se llamará solo cuando el UITextField
sea el first responder
.
iOS Responder Chain y UIEvent
La cadena de respuesta también está involucrada en tocar la pantalla, movimientos, clics. Cuando el sistema detecta algún tipo de evento (táctil, movimiento, control remoto, presión), se crea un UIEvent
debajo del capó y se envía usando el método UIApplication.shared.sendEvent()
a UIWindow
. Después de recibir el evento, UIWindow
determina el uso del hitTest:withEvent
al que UIResponder
pertenece este evento y le asigna el first responder
. El siguiente es el trabajo con una lista vinculada de UIResponder
descritos anteriormente.
Para trabajar con los sistemas UIEvent
, las subclases de UIResponder (UIViewController, UIView, UIApplication)
pueden anular estos 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?)
A pesar de que la capacidad de heredar y llamar a sendEvent
manualmente está presente, UIResponder
no UIResponder
destinado a esto. Esto puede crear muchos problemas con la operación de eventos personalizados, lo que puede conducir a acciones incomprensibles causadas por un first responeder
respondedor aleatorio que puede responder a su evento.
Por qué es útil, dónde usar
A pesar de que UIKit
controla completamente la iOS Responder Chain
de UIKit
de UIKit
, se puede usar para resolver el problema de la delegación / comunicación. UIResponder
acciones de UIResponder
son similares a NotificationCenter.default.post
una sola vez.
Tomemos un ejemplo, tenemos un UIViewController
, que está en lo profundo de la pila de UINavigationController y tenemos que decirle qué sucedió cuando se hizo clic en un botón en otra pantalla. Puede usar el patrón delagate o NotificationCenter.default.post
, pero una opción bastante simple es usar la iOS Responder Chain
.
button.addTarget(nil, action: #selector(RootVC.doSomething), for: .touchUpInside)
Cuando se presiona, se llamará al método en la UIViewController
. #selector puede tomar los siguientes parámetros:
@objc func doSomething() @objc func doSomething(sender: Any?) @objc func doSomething(sender: Any?, event: UIEvent?)
remitente es el objeto que envió el evento: UIButton, UITextField, etc.
Recursos adicionales para el aprendizaje [eng]:
Buena descripción de UIEvent, UIResponder y un par de ejemplos avanzados (coordinador patern)
Lea más sobre la cadena de respuesta ios
Ejemplo de cadena de respuesta en la práctica
Fuera del muelle en la cadena de respuesta de iOS
Fuera del muelle por UIResponder