Dynamische aanroep van methoden is de mogelijkheid om methoden op naam aan te roepen tijdens runtime, en niet tijdens compilatie. In Swift is dit mogelijk door interactie met de Objective-C runtime via de modifiers @objc en dynamic, of door het gebruik van het protocol AnyObject.
Mechanismen:
@objc — markeert een methode/eigenschap/klasse voor export naar de Objective-C runtime.dynamic — vereist dat de aanroep plaatsvindt via de Objective-C message dispatch, en niet via een statische aanroep (vtable).Beperkingen:
@objc.@objc of gemarkeerd door erfelijkheid van NSObject.Voorbeeld:
import Foundation class Person: NSObject { @objc dynamic func sayHello() -> String { return "Hello!" } } let person = Person() // Dynamische aanroep via Selector (perform:): if person.responds(to: #selector(Person.sayHello)) { if let result = person.perform(#selector(Person.sayHello))?.takeUnretainedValue() as? String { print(result) // "Hello!" } }
Evenzo kunnen functies worden aangeroepen via AnyObject met 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!"
Kan een struct dynamische aanroep van methoden ondersteunen via @objc, dynamic of AnyObject?
Antwoord: Nee, alleen klassen die van NSObject erven, of klassen/protocollen met de modifier @objc kunnen dergelijke mechanismen ondersteunen. Structs en enums zijn niet compatibel met de Objective-C runtime, daarom kunnen ze geen dynamische deelnemers zijn.
Verhaal
In het project werd een @objc protocol gebruikt voor de delegate. Een van de ontwikkelaars verwijderde de erfelijkheid van de delegate-klasse van NSObject, waardoor de optionele methoden niet meer bereikbaar waren via optional chaining. De architectuur stopte met werken, en tests begonnen constant te falen.
Verhaal
In een poging om KVO (key-value observing) op een eigenschap van de struct te gebruiken, markeerde de ontwikkelaar deze als dynamic. De code compileerde, maar werkte niet zoals verwacht, omdat structs de Objective-C runtime niet ondersteunen. Dynamische reacties op wijzigingen werkten niet, wat leidde tot gemiste UI-updates.
Verhaal
In de extensie van de klasse vergaten ze de modifier @objc toe te voegen aan de functie die ze aanriepen via perform(_:). Hierdoor traden er crashes op in productie bij de poging om een ongerelateerde selector aan te roepen. De oorzaak werd lang gezocht, totdat ze het ontbreken van de export van de functie naar Objective-C opmerkten.