ProgrammingiOS Developer

How does dynamic method dispatch work in Swift? What mechanisms (such as @objc, dynamic, AnyObject) allow calling methods by name at runtime, and under what conditions is this possible? Provide an example of usage.

Pass interviews with Hintsage AI assistant

Answer

Dynamic method dispatch is the ability to call methods by name at runtime rather than at compile time. In Swift, this is possible through interaction with the Objective-C runtime via the modifiers @objc and dynamic, or through the use of the AnyObject protocol.

Mechanisms:

  • @objc — marks a method/property/class for export to the Objective-C runtime.
  • dynamic — requires execution through Objective-C message dispatch, rather than through a static call (vtable).
  • The AnyObject protocol allows methods to be declared as optional and enables calling them through optional chaining.

Limitations:

  • Works only with classes inheriting from NSObject, or with protocols marked as @objc.
  • Applies only to methods/properties with the @objc attribute or marked through inheritance from NSObject.

Example:

import Foundation class Person: NSObject { @objc dynamic func sayHello() -> String { return "Hello!" } } let person = Person() // Dynamic call via Selector (perform:): if person.responds(to: #selector(Person.sayHello)) { if let result = person.perform(#selector(Person.sayHello))?.takeUnretainedValue() as? String { print(result) // "Hello!" } } }

Similarly, functions can be called through AnyObject with optional chaining:

@objc protocol Greeter { @objc optional func greet() } class Robot: NSObject, Greeter { func greet() { print("Beep-beep!") } } let anyGreeter: AnyObject = Robot() anyGreeter.greet?() // "Beep-beep!"

Tricky Question

Can a struct support dynamic method dispatch through @objc, dynamic, or AnyObject?

Answer: No, only classes inherited from NSObject, or classes/protocols with the @objc modifier can support such mechanisms. Structs and enums are not compatible with the Objective-C runtime, so they cannot be dynamic participants.


Examples of real errors due to lack of knowledge of the topic


Story

In a project, an @objc protocol was used for a delegate. One developer removed the inheritance of the delegate class from NSObject, causing optional methods to become unavailable for calls through optional chaining. The architecture broke down, and tests began to fail constantly.


Story

In an attempt to use KVO (key-value observing) on a struct property, a developer marked it as dynamic. The code compiled but did not work as expected because structs do not support the Objective-C runtime. Dynamic reactions to changes did not work, leading to missed UI updates.


Story

In a class extension, the @objc modifier was forgotten for a function that was called through perform(_:). As a result, crashes occurred in production when trying to call an unlinked selector. The cause was hard to identify until the absence of the function's export to Objective-C was noticed.