@dynamicMemberLookup è un'annotazione di Swift che consente di sovrascrivere l'accesso alle proprietà di un oggetto a runtime tramite subscript. Storicamente, questo meccanismo è stato introdotto per una migliore integrazione con linguaggi dinamici come Python e mira a una routing più flessibile dell'accesso ai dati in proxy object, modelli dinamici e DSL.
Problema: Swift standard richiede di dichiarare esplicitamente le proprietà e verifica la loro esistenza a compile time. Ma a volte è necessario accedere alle proprietà per nome, che non esiste a compile time, per esempio, quando si lavora con JSON, API, proxy object e wrapper per script.
Soluzione: Utilizzare @dynamicMemberLookup e implementare subscript(dynamicMember:) per intercettare i tentativi di accesso a proprietà inesistenti.
Esempio di codice:
@dynamicMemberLookup struct JSON { private var data: [String: Any] subscript(dynamicMember member: String) -> Any? { data[member] } } let user = JSON(data: ["name": "Anna", "age": 23]) print(user.name as? String) // Anna
Caratteristiche principali:
Si può implementare dynamicMemberLookup per classi, o solo per struct?
Sì, può essere applicato a classi, struct ed enum (a partire da Swift 5+). È importante solo implementare il subscript appropriato.
Cosa succede se si accede a una proprietà inesistente tramite dynamicMemberLookup?
Restituisce un valore dal subscript, la responsabilità per la gestione dell'assenza di valore è nella tua implementazione.
Ad esempio, nell'esempio sopra, se si accede a user.secret, restituirà nil.
Si può fare accesso dinamico usando chiavi di un altro tipo, come Int?
Sì! Puoi dichiarare subscript(dynamicMember:) con altri argomenti e combinarlo con subscript normali.
@dynamicMemberLookup struct ArrayProxy { private let array: [Int] subscript(dynamicMember member: String) -> Int? { if member == "first" { return array.first } if member == "last" { return array.last } return nil } subscript(index: Int) -> Int? { array[safe: index] } }
Un sviluppatore utilizza @dynamicMemberLookup per un modello utente normale (User), per accedere a qualsiasi campo tramite stringhe. Il codice diventa opaco, l'IDE ha perso suggerimenti.
Pro:
Contro:
@dynamicMemberLookup è stato applicato per lavorare con un oggetto JSON arbitrario, i cui campi non sono noti in anticipo. Il meccanismo consente di lavorare elegantemente e in modo sicuro (tramite Any?/optional binding) con dati non strutturati.
Pro:
Contro: