Al crear una app de iOS con Swift, quizá te hayas preguntado por qué este controlador de vista recibe el evento al pulsar un botón.
Si rastreas dónde y cómo fluyen los eventos táctiles por la pantalla, encontrarás el patrón Chain of Responsibility en la base.
En resumen, la cadena UIResponder es un ejemplo representativo de cómo Apple implementa a nivel de framework el patrón Chain of Responsibility, uno de los patrones de diseño GoF. Los responders transfieren la responsabilidad al siguiente responder hasta encontrar un objeto capaz de procesar el evento.
En este artículo analizo el código para explicar qué es Chain of Responsibility, cómo funciona realmente la cadena UIResponder y qué ventajas prácticas ofrece conocerla.
Resumen de puntos clave
- Chain of Responsibility es un patrón de diseño en el que varios objetos pasan una solicitud como una cadena hasta encontrar uno que pueda procesarla.
- La cadena UIResponder de iOS implementa este patrón a nivel de framework.
- Un evento táctil sube desde UIView por las supervistas, el controlador de vista, la ventana y la aplicación.
- La propiedad next apunta al siguiente eslabón; si nadie procesa el evento, se descarta sin más.
¿Qué es el patrón Chain of Responsibility?
Chain of Responsibility es un patrón de comportamiento que desacopla débilmente el emisor de una solicitud de su procesador.
Es parecido a tramitar una aprobación en una empresa. Si un asistente puede resolverla, termina ahí; si no, pasa al gerente y, si tampoco puede, al director.
Quien envía la solicitud no necesita saber quién dará la aprobación final. Solo la entrega al primer eslabón y la cadena se encarga de hacerla avanzar.
La clave es que cada objeto procesador solo debe conocer dos cosas: si puede procesar la solicitud y quién es el siguiente objeto si no puede.
Una versión muy sencilla en Swift tendría esta estructura.
class Handler {
var next: Handler? // Siguiente eslabón de la cadena
func handle(_ request: Int) {
// Pasar la responsabilidad al siguiente objeto si no se puede procesar
next?.handle(request)
}
}
Esta estructura, en la que una sola propiedad next conecta la cadena y lo no procesado pasa a next, está integrada directamente en UIResponder.
¿Cómo funciona la cadena UIResponder?
En iOS, todos los objetos que pueden recibir eventos táctiles, de movimiento o de control remoto heredan de UIResponder. UIView, UIViewController, UIWindow y UIApplication son subclases de UIResponder.
Por eso cada uno tiene una propiedad cuyo nombre exacto es next. Está definida en UIResponder.
// UIResponderPropiedad definida en
var next: UIResponder? { get }
Cuando el usuario toca la pantalla, el sistema busca primero la vista más interna que recibió el toque. Esto se llama hit-testing y determina el candidato a first responder.
Si esa vista no procesa el evento, el sistema sigue next hacia arriba. El orden es aproximadamente el siguiente.
- UIView (la vista tocada)
- Sus supervistas
- El UIViewController que administra la vista
- UIWindow
- UIApplication
- UIApplicationDelegate
Si nadie procesa el evento al recorrer toda la cadena, se descarta silenciosamente. La app no se bloquea ni muestra un error; simplemente ignora el evento.
Lo interesante es que next no siempre es la supervista.
Si la vista es la vista raíz de un controlador de vista, next será el controlador de vista, no una supervista.
¿Qué utilidad tiene esto en la práctica?
Sinceramente, al principio la app funciona bien aunque no conozcas esta estructura interna. Pero entenderla cambia claramente la forma de depurar.
Te cuento un caso que viví: un gesto de toque no funcionaba en una vista personalizada.
Al rastrear en orden dónde se detenía el responder, encontré enseguida que la cadena se cortaba porque isUserInteractionEnabled era false en una supervista.
La propagación de eventos personalizados también resulta útil. Puedes definir mensajes que suban por la cadena UIResponder y entregar una acción desde una vista profunda hasta un controlador de vista superior sin delegates.
endEditing(true), usado habitualmente para ocultar el teclado, también utiliza esta cadena. Busca el first responder y llama a resignFirstResponder.
En resumen, entender la cadena UIResponder permite rastrear lógicamente dónde se detuvo un evento y diseñar su propagación hacia arriba sin abusar de los delegates.
Preguntas frecuentes
P. ¿first responder y la cadena responder son conceptos distintos? R. first responder es un único objeto con derecho a recibir primero un evento; la cadena responder es toda la cadena que sube desde ese first responder.
P. ¿next siempre apunta a una supervista? R. No. Una vista normal apunta a su supervista, pero la vista raíz de un controlador de vista tiene como next al controlador de vista.
El nombre Chain of Responsibility puede parecer difícil, pero todo se reduce a un principio sencillo: si no puedes procesarlo, pásalo al siguiente. Espero que este artículo te haya ayudado a entender la estructura oculta de iOS conocida como cadena UIResponder. Cuando encuentres un error en el que un evento no responda, sigue esta cadena eslabón por eslabón.

