WWDC24 SALE: Save 50% on all my Swift books and bundles! >>

How to handle unknown properties and methods using @dynamicMemberLookup

Swift version: 5.10

Paul Hudson    @twostraws   

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:

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

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:

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:

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

That code prints “Ed Sheeran”, because the name property will always be used rather than the dynamic member subscript.

Save 50% in my WWDC sale.

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Available from iOS 8.0

Similar solutions…

About the Swift Knowledge Base

This is part of the Swift Knowledge Base, a free, searchable collection of solutions for common iOS questions.

Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 5.0/5

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.