iOS Responder Chain o lo que preguntan en la entrevista

imagen


¿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 .


imagen


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

Source: https://habr.com/ru/post/464463/


All Articles