0Pricing
Swift Academy · Lección

@dynamicMemberLookup

Construya un acceso dinámico y seguro para los tipos a sus miembros.

@dynamicMemberLookup es una lección gratuita de Swift Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Swift Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Swift Academy incluye 4 lecciones en total.

¿Qué es la búsqueda dinámica de miembros?

El atributo @dynamicMemberLookup permite que un tipo responda al acceso a miembros mediante sintaxis de punto cuando estos no están declarados como propiedades reales. Cuando escribe value.something, Swift lo redirige a un subíndice especial que usted define.

Esto proporciona una apariencia natural a los tipos envoltorio y mantiene el acceso centralizado.

@dynamicMemberLookup
struct Settings {
    private var storage: [String: String] = ["theme": "dark"]
    subscript(dynamicMember key: String) -> String? {
        storage[key]
    }
}

let s = Settings()
print(s.theme ?? "none")

El subíndice obligatorio

Un tipo marcado con @dynamicMemberLookup debe implementar subscript(dynamicMember:). Cuando el parámetro es un String, el nombre del miembro que escriba se convierte en esa cadena en tiempo de ejecución.

Por tanto, config.timeout llama al subíndice con la clave "timeout".

@dynamicMemberLookup
struct Config {
    let values: [String: Int]
    subscript(dynamicMember member: String) -> Int {
        values[member] ?? 0
    }
}

let config = Config(values: ["timeout": 30, "retries": 3])
print(config.timeout)
print(config.retries)

La búsqueda mediante String no es segura respecto a tipos

La búsqueda dinámica de miembros basada en cadenas es flexible, pero pierde la comprobación en tiempo de compilación. Si escribe mal un miembro, el código sigue compilando y obtiene lo que el subíndice devuelva para una clave inexistente.

A continuación, un miembro desconocido devuelve silenciosamente el valor predeterminado en lugar de provocar un error de compilación.

@dynamicMemberLookup
struct Config {
    let values: [String: Int]
    subscript(dynamicMember member: String) -> Int {
        values[member] ?? -1
    }
}

let config = Config(values: ["timeout": 30])
print(config.tmout)

Búsqueda segura respecto a tipos mediante rutas de claves

Para mayor seguridad, puede hacer que el subíndice reciba un KeyPath en lugar de una cadena. Ahora el compilador verifica que el miembro exista en el tipo envuelto, recuperando la comprobación completa y manteniendo el reenvío del acceso.

Este patrón es ideal para tipos envoltorio que contienen un valor con tipo definido.

struct User { let name: String; let age: Int }

@dynamicMemberLookup
struct Boxed {
    let user: User
    subscript<T>(dynamicMember path: KeyPath<User, T>) -> T {
        user[keyPath: path]
    }
}

let boxed = Boxed(user: User(name: "Ada", age: 36))
print(boxed.name)
print(boxed.age)

Por qué la versión con ruta de claves es más segura

Como el subíndice recibe un KeyPath<User, T>, solo se permiten los miembros que realmente existen en User. Un error tipográfico como boxed.naem ahora impediría la compilación, a diferencia de la versión basada en cadenas.

Obtiene la comodidad de la sintaxis de punto sin ninguno de sus riesgos.

struct User { let name: String; let age: Int }

@dynamicMemberLookup
struct ReadOnly {
    let value: User
    subscript<T>(dynamicMember path: KeyPath<User, T>) -> T {
        value[keyPath: path]
    }
}

let r = ReadOnly(value: User(name: "Lin", age: 22))
print(r.name, r.age)

Miembros dinámicos modificables

Si el subíndice proporciona un setter y recibe un WritableKeyPath, también puede asignar valores a los miembros reenviados. El envoltorio pasa la escritura directamente al valor envuelto.

Esto permite crear un envoltorio mutable transparente.

struct Profile { var name: String; var score: Int }

@dynamicMemberLookup
struct Wrapper {
    var value: Profile
    subscript<T>(dynamicMember path: WritableKeyPath<Profile, T>) -> T {
        get { value[keyPath: path] }
        set { value[keyPath: path] = newValue }
    }
}

var w = Wrapper(value: Profile(name: "Mo", score: 0))
w.score = 99
print(w.value.score)

Reenviar a un objeto envuelto

La búsqueda dinámica de miembros es excelente para proxies ligeros que principalmente reenvían las operaciones a un valor interno, pero añaden un poco de comportamiento. El subíndice mantiene la lógica de reenvío en un solo lugar.

Aquí un envoltorio de registro reenvía las lecturas e imprime a qué miembro se accedió.

struct Account { let id: Int; let balance: Double }

@dynamicMemberLookup
struct Logged {
    let account: Account
    subscript<T>(dynamicMember path: KeyPath<Account, T>) -> T {
        let result = account[keyPath: path]
        print("accessed a member")
        return result
    }
}

let logged = Logged(account: Account(id: 7, balance: 100))
print(logged.balance)

Combinar con conceptos de llamadas dinámicas

La búsqueda dinámica de miembros se combina bien con los genéricos. Un solo subíndice genérico puede reenviar cualquier tipo de propiedad, por lo que un único envoltorio sirve para valores de muchas formas.

Aquí el mismo Proxy funciona tanto si el miembro es un String como si es un Int.

struct Item { let title: String; let count: Int }

@dynamicMemberLookup
struct Proxy<Wrapped> {
    let wrapped: Wrapped
    subscript<T>(dynamicMember path: KeyPath<Wrapped, T>) -> T {
        wrapped[keyPath: path]
    }
}

let proxy = Proxy(wrapped: Item(title: "Book", count: 4))
print(proxy.title, proxy.count)

Búsqueda mediante String para datos similares a JSON

La variante basada en cadenas sigue teniendo su utilidad: representar datos poco estructurados, como JSON analizado, cuyos miembros no se conocen en tiempo de compilación. Cada acceso se convierte en una búsqueda en un diccionario.

Aquí un pequeño valor similar a JSON expone sus campos mediante la sintaxis de punto.

@dynamicMemberLookup
struct JSON {
    let fields: [String: String]
    subscript(dynamicMember key: String) -> String {
        fields[key] ?? ""
    }
}

let json = JSON(fields: ["city": "Oslo", "country": "Norway"])
print(json.city)
print(json.country)

Limitaciones que debe tener en cuenta

La búsqueda dinámica de miembros solo afecta a la sintaxis de acceso a miembros; no añade propiedades almacenadas reales. Las herramientas, como el autocompletado, funcionan con la variante de ruta de claves, pero no con claves de cadena arbitrarias.

Prefiera la variante de ruta de claves siempre que se conozca la estructura subyacente y reserve la variante basada en cadenas para datos realmente dinámicos.

struct Point { let x: Int; let y: Int }

@dynamicMemberLookup
struct Safe {
    let point: Point
    subscript<T>(dynamicMember path: KeyPath<Point, T>) -> T {
        point[keyPath: path]
    }
}

let safe = Safe(point: Point(x: 3, y: 4))
print(safe.x + safe.y)

Un decorador práctico

Como aplicación conjunta de estos conceptos, este es un envoltorio medido que reenvía cada lectura de propiedad a su valor interno y cuenta los accesos. Los frameworks reales usan esta idea para la observación y el tracing.

La sintaxis de punto del envoltorio resulta idéntica a la forma de usar el valor directamente.

struct Sensor { let temperature: Double; let humidity: Double }

@dynamicMemberLookup
class Tracked {
    let sensor: Sensor
    var reads = 0
    init(_ s: Sensor) { sensor = s }
    subscript<T>(dynamicMember path: KeyPath<Sensor, T>) -> T {
        reads += 1
        return sensor[keyPath: path]
    }
}

let t = Tracked(Sensor(temperature: 21.5, humidity: 0.4))
print(t.temperature)
print(t.humidity)
print(t.reads)

Comprobación rápida: búsqueda dinámica segura respecto a tipos

Recuerde qué parámetro del subíndice hace que la búsqueda dinámica de miembros sea segura respecto a tipos.

Repaso: búsqueda dinámica de miembros

Ha aprendido cómo funciona @dynamicMemberLookup:

  • El atributo redirige el acceso con sintaxis de punto no declarado a subscript(dynamicMember:).
  • Un parámetro String proporciona un acceso flexible, pero sin comprobación de tipos, ideal para datos similares a JSON.
  • Un parámetro KeyPath recupera la seguridad de tipos completa y el autocompletado.
  • Un WritableKeyPath con un setter permite reenviar las escrituras a través de un wrapper.
  • Es una comodidad sintáctica que combina de forma natural con los patrones proxy y decorator.

Ahora dispone del conjunto completo de herramientas de key paths: lectura, escritura, uso con colecciones y reenvío dinámico.

struct User { let name: String }

@dynamicMemberLookup
struct Wrap {
    let user: User
    subscript<T>(dynamicMember path: KeyPath<User, T>) -> T {
        user[keyPath: path]
    }
}

print(Wrap(user: User(name: "Final")).name)

Preguntas frecuentes

¿La lección «@dynamicMemberLookup» es gratis?

Sí — el texto completo de «@dynamicMemberLookup» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Swift Academy, actualiza a CoddyKit PRO. El curso de Swift Academy incluye 4 lecciones en total.

¿Qué aprenderé en «@dynamicMemberLookup»?

Construya un acceso dinámico y seguro para los tipos a sus miembros. Practicas Swift Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Swift Academy?

No se requiere experiencia previa. Swift Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «@dynamicMemberLookup»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Swift Academy?

Sí. Cada lección de Swift Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Fundamentos de KeyPath
  2. Uso de KeyPaths en colecciones
  3. KeyPaths modificables y de referencia
  4. @dynamicMemberLookup
← Volver a Swift Academy