El envío de métodos es un algoritmo utilizado para seleccionar el método apropiado que debe invocarse tras una llamada. El objetivo principal del envío de métodos es proporcionar al programa información sobre dónde puede encontrar el código ejecutable para un método específico en la memoria.
Los lenguajes compilados tienen tres tipos de envío de métodos:
El envío estático es el método de envío más rápido en Swift. Como no hay anulación de métodos disponible, solo hay una implementación del método, y reside en una única ubicación en la memoria.
\ Podemos usar el envío estático utilizando palabras clave como static, final, private.
\ El envío estático es un método de envío predeterminado para los tipos de valor, ya que los tipos de valor no pueden ser anulados.
\ Veamos algunos ejemplos:
Una vez que agregamos la palabra clave final a una clase, sus métodos no admiten anulación, y es aquí cuando entra en juego el envío estático.
// MARK: Final class final class ClassExample { // MARK: Static dispatch func method() { // implementation ... } }
Una vez que agregas una implementación predeterminada de un protocolo usando una extensión, su método de envío cambia a envío estático en lugar de usar una Tabla de Testigos.
// MARK: Prorocol Extension extension ProtocolExample { // MARK: Direct Dispatch func method() { // implementation ... } } class ClassExample2: ProtocolExample {} let classExample2 = ClassExample2() classExample2.method()
Cuando un método se implementa en una extensión, significa que no puede ser anulado por subclases. En este caso, hay espacio para el envío estático.
// MARK: Example Class Extension class ClassExample3 {} extension ClassExample3 { // MARK: Direct Dispatch func method() { // implementation ... } } let classExample3 = ClassExample3() classExample3.method()
No podemos acceder a un método privado fuera del cuerpo de la clase. Esto significa que el método no puede ser anulado y utiliza envío estático.
// MARK: Access Control class ClassExample4 { // MARK: Direct Dispatch private func method() { // implementation ... } }
El envío por tabla se utiliza cuando tenemos que lidiar con la herencia. Este es un tipo de envío predeterminado utilizado en Swift.
Para cada instancia de una clase o subclase, se crea una tabla virtual que contiene información sobre los métodos implementados para cada clase y almacena una referencia a la implementación apropiada. La principal desventaja del envío por tabla virtual es que tiene una velocidad menor que el envío estático.
\ Veamos un ejemplo:
// MARK: Virtual Table class ParentClass { func method1() {} func methdod2() {} } class ChildClass: ParentClass { override func method1() {} func method3() {} }
\ Para cada instancia, se crea su propia tabla virtual de la siguiente manera:
\
Una Tabla de Testigos es utilizada por protocolos y se crea para cada clase que se ajusta al protocolo. La CPU utiliza esta tabla para determinar dónde debe buscar una implementación apropiada. Cada tipo (valor y referencia) que se ajusta a un protocolo tiene su propia Tabla de Testigos de Protocolo, que contiene punteros a los métodos del tipo requeridos por el protocolo.
\ Veamos un ejemplo:
// MARK: Witness Table Dispatch protocol ProtocolExample { func method1() func method2() } class ClassExample1: ProtocolExample { func method1() {} func method2() {} } class ClassExample2: ProtocolExample { func method1() {} func method2() {} }
\ En este caso, se crea una tabla de testigos para cada clase:
\
El Envío de Mensajes es el estilo de envío de métodos más dinámico. Busca una implementación apropiada durante el tiempo de ejecución. Debido a que opera durante el tiempo de ejecución, podemos usar Method Swizzling para cambiar las implementaciones de métodos.
\ Si deseas utilizar el envío de mensajes, debes agregar @objc dynamic antes de una implementación de método.
// MARK: Message Dispatch class ClassExample: NSObject { @objc dynamic func method() {} } class SubClassExample: ClassExample { @objc dynamic override func method() {} } let subclass = SubClassExample() subclass.method()
\ La implementación del método se busca dentro de SubClassExample. Si no hay implementación de este método en esa clase, la búsqueda continúa en la clase padre, y así sucesivamente hasta que llega a NSObject.
\
Combinemos todos los tipos en una sola tabla:
\
En resumen, el envío de métodos en Swift es un aspecto crítico de la ejecución del código, que impacta en el rendimiento y la flexibilidad. Al elegir el método de envío correcto, los desarrolladores pueden optimizar su código, garantizar la adaptabilidad y aprovechar efectivamente las características dinámicas de Swift. Comprender y dominar el envío de métodos es esencial para construir aplicaciones Swift eficientes y adaptables.


