programowanieiOS deweloper

Jak działa dynamiczne wywołanie metod w Swift? Jakie mechanizmy (np. @objc, dynamic, AnyObject) pozwalają na wywoływanie metod po nazwie w czasie wykonania, i w jakich warunkach jest to możliwe? Podaj przykład użycia.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

Dynamiczne wywołanie metod to możliwość wywoływania metod po nazwie w czasie wykonania (runtime), a nie w czasie kompilacji. W Swift jest to możliwe dzięki interakcji z Objective-C runtime dzięki modyfikatorom @objc i dynamic, lub przy użyciu protokołu AnyObject.

Mechanizmy:

  • @objc — oznacza metodę/właściwość/klasę do eksportu do Objective-C runtime.
  • dynamic — wymaga wykonania za pomocą Objective-C message dispatch, a nie przez statyczne wywołanie (tabela vtable).
  • Protokół AnyObject pozwala deklarować metody jako opcjonalne i umożliwia ich wywoływanie za pomocą optional chaining.

Ograniczenia:

  • Działa tylko z klasami dziedziczącymi z NSObject, lub z protokołami oznaczonymi jako @objc.
  • Dotyczy tylko metod/właściwości z atrybutem @objc lub oznaczonych przez dziedziczenie z NSObject.

Przykład:

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

Podobnie, można wywoływać funkcje przez AnyObject z 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!"

Pytanie z haczykiem

Czy struct może wspierać dynamiczne wywołanie metod przez @objc, dynamic lub AnyObject?

Odpowiedź: Nie, tylko klasy dziedziczące z NSObject, lub klasy/protokóły z modyfikatorem @objc mogą wspierać takie mechanizmy. Struct i enum nie są zgodne z Objective-C runtime, więc nie mogą być dynamicznymi uczestnikami.


Przykłady rzeczywistych błędów z powodu nieznajomości tematów


Historia

W projekcie używano protokołu @objc dla delegata. Jeden z programistów usunął dziedziczenie klasy delegata z NSObject, w wyniku czego opcjonalne metody przestały być dostępne do wywołania przez optional chaining. Architektura przestała działać, testy zaczęły ciągle padać.


Historia

W próbie użycia KVO (key-value observing) na właściwości struktury, programista oznaczył ją jako dynamic. Kod skompilował się, ale nie działał zgodnie z oczekiwaniami, ponieważ struct nie wspiera Objective-C runtime. Dynamiczna reakcja na zmiany nie działała, co prowadziło do pominięcia aktualizacji UI.


Historia

W rozszerzeniu klasy zapomniano dodać modyfikator @objc do funkcji, którą wywoływano przez perform(_:). W rezultacie na produkcji występowały awarie podczas próby wywołania niepowiązanego selektora. Powód długo szukano, aż zauważono brak eksportu funkcji do Objective-C.