Swift version: 5.10
Swift has always had strong focus on type safety, but sometimes you need to be able to work with data where the structure isn’t known ahead of time.
To handle this situation, Swift has an attribute called @dynamicMemberLookup
, which instructs Swift to call a subscript method when accessing properties. This subscript method, subscript(dynamicMember:)
, is required when using the @dynamicMemberLookup
attribute – you’ll get passed the string name of the property that was requested, and can return any value you like.
To help you understand the basics, here’s an example that creates a Person
struct that reads its values from a dictionary:
@dynamicMemberLookup
struct Person {
subscript(dynamicMember member: String) -> String {
let properties = ["name": "Taylor Swift", "city": "Nashville"]
return properties[member, default: ""]
}
}
The @dynamicMemberLookup
attribute requires the type to implement a subscript(dynamicMember:)
method to handle the work of dynamic member lookup. As you can see, I’ve written one that accepts the member name as string and returns a string, and internally it just looks up the member name in a dictionary and returns its value.
That struct allows us to write code like this:
let person = Person()
print(person.name)
print(person.city)
print(person.nameOfPet)
That will compile cleanly and run, even though name
, city
, and nameOfPet
do not exist as properties on the Person
type. Instead, they are all looked up at runtime: that code will print “Taylor Swift” and “Nashville” for the first two calls to print()
, then an empty string for the final one because our dictionary doesn’t store anything for nameOfPet
.
This subscript(dynamicMember:)
method must return a string, which is what enforces Swift’s type safety – even though you’re still dealing with dynamic data, Swift will ensure you get back what you expected.
If you want multiple different types, just implement different subscript(dynamicMember:)
methods:
@dynamicMemberLookup
struct Employee {
subscript(dynamicMember member: String) -> String {
let properties = ["name": "Taylor Swift", "city": "Nashville"]
return properties[member, default: ""]
}
subscript(dynamicMember member: String) -> Int {
let properties = ["age": 26, "height": 178]
return properties[member, default: 0]
}
}
Now that any property can be accessed in more than one way, it’s important that you are clear which one should be used. That might be implicit, for example if you send the return value into a function that accepts only strings, or it might be explicit, like this:
let employee = Employee()
let age: Int = employee.age
Either way, Swift must know for sure which subscript will be called.
You can also overload subscript
to return closures:
@dynamicMemberLookup
struct User {
subscript(dynamicMember member: String) -> (_ input: String) -> Void {
return {
print("Hello! I live at the address \($0).")
}
}
}
let user = User()
user.printAddress("123 Swift Street")
When that’s run, user.printAddress
returns a closure that prints out a string, and the ("123 Swift Street")
part immediately calls it with that input.
Using dynamic member subscripting in a type that has also regular properties and methods will result in those properties and methods always being used in place of the dynamic member. For example, we could define a Singer
struct with a built-in name
property alongside a dynamic member subscript:
struct Singer {
public var name = "Ed Sheeran"
subscript(dynamicMember member: String) -> String {
return "Taylor Swift"
}
}
let singer = Singer()
print(singer.name)
That code prints “Ed Sheeran”, because the name
property will always be used rather than the dynamic member subscript.
SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until September 29th.
Sponsor Hacking with Swift and reach the world's largest Swift community!
Available from iOS 8.0
This is part of the Swift Knowledge Base, a free, searchable collection of solutions for common iOS questions.
Link copied to your pasteboard.