ProgramaciónDesarrollador de iOS

¿Cómo funciona la llamada dinámica de métodos en Swift? ¿Qué mecanismos (por ejemplo, @objc, dynamic, AnyObject) permiten llamar a métodos por nombre en tiempo de ejecución, y bajo qué condiciones es esto posible? Proporcione un ejemplo de uso.

Supere entrevistas con el asistente de IA Hintsage

Respuesta

La llamada dinámica de métodos es la capacidad de invocar métodos por nombre en tiempo de ejecución, en lugar de en tiempo de compilación. En Swift, esto es posible a través de la interacción con el runtime de Objective-C gracias a los modificadores @objc y dynamic, o al usar el protocolo AnyObject.

Mecanismos:

  • @objc — marca el método/propiedad/clase para exportación al runtime de Objective-C.
  • dynamic — requiere la ejecución a través del despacho de mensajes de Objective-C, y no a través de la llamada estática (tabla vtable).
  • El protocolo AnyObject permite declarar métodos como opcionales y permite llamarlos a través de optional chaining.

Limitaciones:

  • Funciona solo con clases que heredan de NSObject, o con protocolos marcados como @objc.
  • Solo se aplica a métodos/propiedades con el atributo @objc o marcados mediante herencia de NSObject.

Ejemplo:

import Foundation class Person: NSObject { @objc dynamic func sayHello() -> String { return "¡Hola!" } } let person = Person() // Llamada dinámica a través de Selector (perform:): if person.responds(to: #selector(Person.sayHello)) { if let result = person.perform(#selector(Person.sayHello))?.takeUnretainedValue() as? String { print(result) // "¡Hola!" } }

De manera similar, se pueden llamar funciones a través de AnyObject con 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!"

Pregunta capciosa

¿Puede una struct soportar la llamada dinámica de métodos a través de @objc, dynamic o AnyObject?

Respuesta: No, solo las clases heredadas de NSObject, o las clases/protocolos con el modificador @objc pueden soportar tales mecanismos. Las struct y enum no son compatibles con el runtime de Objective-C, por lo que no pueden ser participantes dinámicos.


Ejemplos de errores reales debido a falta de conocimiento de los matices del tema


Historia

En el proyecto se utilizó un protocolo @objc para el delegado. Uno de los desarrolladores eliminó la herencia de la clase delegada de NSObject, lo que provocó que los métodos opcionales dejaran de estar disponibles para su llamada a través de optional chaining. La arquitectura dejó de funcionar y las pruebas comenzaron a fallar.


Historia

En un intento de utilizar KVO (observación de clave-valor) en la propiedad de una struct, el desarrollador la marcó como dynamic. El código se compiló, pero no funcionó como se esperaba, ya que la struct no soporta el runtime de Objective-C. La reacción dinámica a los cambios no funcionó, lo que llevó a actualizaciones de UI perdidas.


Historia

En la extensión de una clase, olvidaron agregar el modificador @objc a la función que se llamaba a través de perform(_:). Como resultado, ocurrían fallas en producción al intentar llamar a un selector no relacionado. La causa se buscó durante mucho tiempo hasta que se notó la falta de exportación de la función a Objective-C.