Diseño de software

Patrón Memento en Swift: guía completa (ejemplo de implementación de Undo)

¿Alguna vez te has quedado bloqueado al crear un botón de «Deshacer» en una app de iOS?

4 min de lectura
Imagen de portada de Patrón Memento en Swift: guía completa (ejemplo de implementación de Undo)

¿Alguna vez te has quedado bloqueado al crear un botón de «Deshacer» en una app de iOS?

En una app de edición de texto, permitir que el usuario revierta su última edición empieza por decidir cómo conservar el estado anterior.

Si haces copias de seguridad de las propiedades internas del objeto en distintos lugares, el código se ensucia rápidamente.

Aquí encaja perfectamente el patrón Memento de Swift. Hoy explicaré, con código y desde mi experiencia, cómo guardar y restaurar el estado de un objeto de forma elegante con este patrón.

El patrón Memento guarda externamente el estado interno de un objeto sin romper la encapsulación y permite restaurarlo más adelante.

En una frase: «tomar una instantánea». Es la base de funciones como Undo, los guardados de partidas y el almacenamiento temporal de formularios.


¿Qué es el patrón Memento? Empieza por sus tres roles 🧩

El patrón Memento tiene exactamente tres participantes. Si entiendes estos, ya has recorrido la mitad del camino.

  • Originator (objeto originador): El protagonista que posee el estado. Lo guarda como Memento y lo restaura a partir de uno.
  • Memento: Una instantánea con el estado en un momento concreto. Lo ideal es que su contenido no cambie una vez creada.
  • Caretaker (gestor): Se encarga de conservar los Memento. Normalmente, esta función corresponde a una pila de Undo.

La clave es que el gestor no mira dentro del Memento.

El gestor solo recibe las instantáneas, las apila y las devuelve cuando hacen falta. Solo el objeto originador conoce su estructura interna.

Así se mantiene la encapsulación. Esa es la mayor ventaja del patrón Memento.


¿Cómo se implementa el patrón Memento en Swift?

Tomemos como ejemplo un editor de texto sencillo. Primero definimos el Memento y el objeto originador.

A continuación se muestran el Memento que contiene el estado y el objeto originador que lo crea y restaura.

// Instantánea del estado: no modificar después de crearla let
struct EditorMemento {
    let text: String
}

final class TextEditor {
    var text: String = ""
    func save() -> EditorMemento { EditorMemento(text: text) }   // Guardar
    func restore(_ memento: EditorMemento) { text = memento.text } // Restaurar
}

save()toma una instantánea del estado actual y restore(_:)restaura la instantánea recibida.

La clave es que la propiedad de EditorMementosea let, para que el estado guardado no pueda modificarse después.

Separar save y restore ya deja el código así de limpio
Separar save y restore ya deja el código así de limpio

En la práctica: crear una función de Undo ⏪

Ahora añadiremos el gestor, es decir, la pila de Undo. Su función es acumular los Memento creados antes.

final class UndoManager {
    private var history: [EditorMemento] = []
    func backup(_ memento: EditorMemento) { history.append(memento) }
    func undo() -> EditorMemento? { history.popLast() } // Extraer el estado más reciente
}

El flujo real es el siguiente.

Este es el flujo de guardado y restauración visto en un diagrama
Este es el flujo de guardado y restauración visto en un diagrama

Justo antes de que el usuario edite el texto, guardamos el estado actual mediante backup.

Al pulsar «Deshacer», undoextrae la última instantánea y el objeto originador la restore.

Al integrarlo, la lógica de edición y la de guardado quedaron claramente separadas, y el código resultó mucho más limpio.

Aunque se mezclen varios tipos de edición, como añadir o eliminar texto y cambiar el formato, el método de guardado se unifica y el mantenimiento resulta más sencillo.

Un solo botón de Deshacer funciona sobre este patrón
Un solo botón de Deshacer funciona sobre este patrón

Consejos al estilo Swift: usar Codable y struct

Muchos artículos explican el patrón Memento tomando como referencia lenguajes como Java. En Swift, aprovechar las características del lenguaje lo hace mucho más cómodo.

Primero, structencaja mejor con un Memento que class. Al ser un tipo por valor, al copiarlo se convierte en una instantánea independiente. Se reduce así el riesgo de que el original cambie por referencias entrelazadas.

Segundo, adoptar Codableen el Memento facilita guardar el estado en un archivo o en UserDefaults. Incluso puedes ampliarlo para conservar los guardados después de cerrar y volver a abrir la app.

Tercero, si usas UIKit, te recomiendo revisar primero la clase del sistema UndoManager. Antes de implementarlo por tu cuenta, conviene conocer las herramientas estándar.


Preguntas frecuentes (Q&A)

P. ¿No basta con hacer una copia en variables?

En casos sencillos, sí. Pero cuando hay varios estados o la lógica de guardado y restauración se complica, el código de copia disperso se convierte en un foco de errores. El patrón Memento lo centraliza.

P. ¿No consumirá demasiada memoria?

Es cierto. Acumular instantáneas indefinidamente aumenta la presión sobre la memoria. Por eso, en la práctica, suele limitarse el historial a unas 20–50 entradas o guardarse solo las partes modificadas.


El patrón Memento puede tener un nombre poco familiar, pero en realidad es la sencilla idea de «tomar instantáneas y revertir».

Si estás pensando en implementar Undo o almacenamiento temporal, prueba a seguir el código de ejemplo de hoy. Notarás enseguida cómo gestionar el estado manteniendo la encapsulación. ¡Ánimo! 😊

Lecturas recomendadas