0Pricing
Swift Academy · Aula

@dynamicMemberLookup

Crie acesso dinâmico e seguro quanto aos tipos aos membros.

@dynamicMemberLookup é uma aula grátis de Swift Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Swift Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Swift Academy inclui 4 aulas no total.

O que é a busca dinâmica de membros?

O atributo @dynamicMemberLookup permite que um tipo responda ao acesso de membros com sintaxe de ponto quando eles não estão declarados como propriedades reais. Quando você escreve value.something, Swift o encaminha para um subscrito especial definido por você.

Isso dá aos tipos encapsuladores uma aparência natural, mantendo o acesso em um único lugar.

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

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

O subscrito obrigatório

Um tipo marcado com @dynamicMemberLookup precisa implementar subscript(dynamicMember:). Quando o parâmetro é uma String, o nome do membro digitado se torna essa cadeia de caracteres em tempo de execução.

Assim, config.timeout chama o subscrito com a chave "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)

A busca por cadeia de caracteres não é segura quanto aos tipos

A busca dinâmica de membros baseada em cadeias de caracteres é flexível, mas perde a verificação em tempo de compilação. Se você escrever um membro incorretamente, o código ainda será compilado e você receberá o que quer que o subscrito retorne para uma chave ausente.

Abaixo, um membro desconhecido retorna silenciosamente o valor padrão em vez de fazer a compilação falhar.

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

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

Busca segura quanto aos tipos com caminhos de chave

Para obter segurança, você pode fazer o subscrito receber um KeyPath em vez de uma cadeia de caracteres. Agora o compilador verifica se o membro existe no tipo encapsulado, restaurando a verificação completa e mantendo o encaminhamento do acesso.

Esse padrão é ideal para tipos encapsuladores que contêm um valor fortemente tipado.

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 que a versão com caminho de chave é mais segura

Como o subscrito recebe um KeyPath<User, T>, somente membros que realmente existem em User são permitidos. Um erro de digitação como boxed.naem agora faria a compilação falhar, ao contrário do que ocorre na versão baseada em cadeias de caracteres.

Você obtém a conveniência da sintaxe de ponto sem nenhum risco desse tipo.

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)

Membros dinâmicos graváveis

Se o subscrito fornecer um definidor e receber um WritableKeyPath, você também poderá atribuir valores aos membros encaminhados. O encapsulador repassa a escrita diretamente para o valor encapsulado.

Isso cria um encapsulador mutável e 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)

Encaminhando para um objeto encapsulado

A busca dinâmica de membros é excelente para proxies leves que encaminham principalmente para um valor interno, mas adicionam um pouco de comportamento. O subscrito mantém a lógica de encaminhamento em um único lugar.

Aqui, um encapsulador de registro encaminha as leituras e imprime qual membro foi acessado.

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)

Combinando com ideias de chamadas dinâmicas

A busca dinâmica de membros combina bem com genéricos. Um único subscrito genérico pode encaminhar qualquer tipo de propriedade, portanto um encapsulador serve para valores de muitos formatos.

Aqui o mesmo Proxy funciona tanto quando o membro é uma cadeia de caracteres quanto quando é um inteiro.

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)

Busca por cadeia de caracteres para dados semelhantes a JSON

A forma baseada em cadeias de caracteres ainda tem seu lugar: representar dados pouco estruturados, como JSON analisado, nos quais os membros não são conhecidos em tempo de compilação. Cada acesso se torna uma busca em dicionário.

Aqui, um pequeno valor semelhante a JSON expõe seus campos por meio da sintaxe de ponto.

@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)

Limitações a ter em mente

A busca dinâmica de membros afeta apenas a sintaxe de acesso a membros; ela não adiciona propriedades armazenadas reais. Ferramentas como o preenchimento automático funcionam para a forma com caminho de chave, mas não para chaves arbitrárias baseadas em cadeias de caracteres.

Prefira a versão com caminho de chave sempre que a estrutura subjacente for conhecida e reserve a versão baseada em cadeias de caracteres para dados genuinamente 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)

Um decorador prático

Reunindo tudo, este é um encapsulador medido que encaminha cada leitura de propriedade para seu valor wrapped enquanto conta os acessos. Frameworks reais usam essa ideia para observação e rastreamento.

A sintaxe de ponto no encapsulador parece idêntica ao uso direto do valor.

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)

Verificação rápida: busca dinâmica segura quanto aos tipos

Lembre-se de qual parâmetro do subscrito torna a busca dinâmica de membros segura quanto aos tipos.

Recapitulação: Pesquisa dinâmica de membros

Você aprendeu como @dynamicMemberLookup funciona:

  • O atributo encaminha acessos à sintaxe de ponto não declarados para subscript(dynamicMember:).
  • Um parâmetro String oferece acesso flexível, mas sem verificação, ideal para dados semelhantes a JSON.
  • Um parâmetro KeyPath restaura a segurança total de tipos e o preenchimento automático.
  • Um WritableKeyPath com um modificador permite encaminhar escritas por meio de um wrapper.
  • É uma conveniência de sintaxe que combina naturalmente com os padrões de proxy e decorador.

Agora você tem o conjunto completo de ferramentas de caminhos de chave: leitura, escrita, uso com coleções e encaminhamento 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)

Perguntas Frequentes

A aula “@dynamicMemberLookup” é grátis?

Sim — o texto completo de “@dynamicMemberLookup” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Swift Academy, atualize para CoddyKit PRO. O curso de Swift Academy inclui 4 aulas no total.

O que vou aprender em “@dynamicMemberLookup”?

Crie acesso dinâmico e seguro quanto aos tipos aos membros. Você pratica Swift Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Swift Academy?

Nenhuma experiência prévia é necessária. Swift Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “@dynamicMemberLookup”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Swift Academy?

Sim. Cada aula de Swift Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Noções Básicas de KeyPath
  2. Uso de KeyPaths em Coleções
  3. KeyPaths Graváveis e de Referência
  4. @dynamicMemberLookup
← Voltar para Swift Academy