ProgrammingiOS Developer

What is dynamic member lookup in Swift, what is @dynamicMemberLookup used for, and how to implement dynamic property routing through this mechanism?

Pass interviews with Hintsage AI assistant

Answer.

@dynamicMemberLookup is a Swift annotation that allows you to override access to an object's properties at runtime via subscript. Historically, this mechanism was introduced for more transparent integration with dynamic languages like Python, and it is aimed at more flexible data access routing in proxy objects, dynamic models, and DSLs.

Problem: Standard Swift requires properties to be explicitly declared and checks their existence at compile time. However, sometimes it is necessary to access properties by their names, which do not exist at compile time, such as when dealing with JSON, APIs, proxy objects, and script wrappers.

Solution: Use @dynamicMemberLookup and implement subscript(dynamicMember:) to intercept access attempts to non-existent properties.

Code example:

@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

Key features:

  • Allows access to properties whose names are unknown at compile time.
  • Uses subscript(dynamicMember:) for routing to the required value.
  • Does not limit you to specific types of values or selection logic.

Tricky questions.

Can dynamicMemberLookup be implemented for classes, or only for structs?

Yes, it can be applied to classes, structs, and enums (starting from Swift 5+). It is important to implement the corresponding subscript.

What happens if you access a non-existent property through dynamicMemberLookup?

It returns a value from the subscript; the responsibility for handling the absence of a value lies with your implementation.

For example, in the above example, if you access user.secret, nil will be returned.

Can dynamic access be done using keys of another type, such as Int?

Yes! You can declare subscript(dynamicMember:) with different argument labels and combine it with regular subscripts.

@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] } }

Common mistakes and anti-patterns

  • Using dynamicMemberLookup for regular models, where the set of properties is known — reduces code readability and maintainability.
  • Type errors: the absence of explicit value checks and returning nil instead of crashing can lead to silent failures.
  • Debugging difficulties: IDE cannot show autocomplete for dynamic properties.

Real-life example

Negative case

A developer uses @dynamicMemberLookup for a regular user model (User) to access any fields via strings. The code becomes opaque, and the IDE lost hints.

Pros:

  • Flexible, can access dynamic properties

Cons:

  • Loss of autocomplete
  • Difficult to read and maintain the project
  • Many runtime errors

Positive case

@dynamicMemberLookup is applied for working with arbitrary JSON objects whose fields are unknown in advance. The mechanism allows for elegant and safe (through Any?/optional binding) handling of unstructured data.

Pros:

  • Beautiful integration of scripts, JSON, external APIs
  • Flexibility without sacrificing compile-time safety

Cons:

  • Still requires caution when casting types, nil values are possible