Comprensión del tiempo de ejecución de iOS
Descripción general: Runtime, también llamado runtime, es un conjunto de API de lenguaje C subyacentes y es uno de los núcleos del sistema iOS. Los desarrolladores pueden enviar mensajes a cualquier objeto durante el proceso de codificación. Durante la fase de compilación, solo determinan enviar el mensaje al receptor. La forma en que el receptor responde y procesa el mensaje depende del tiempo de ejecución. En lenguaje C, el compilador determina qué función llamar, mientras que las funciones OC pertenecen a un proceso de llamada dinámica. El compilador realmente no puede decidir qué función llamar y solo se puede determinar durante el tiempo de ejecución real. la función y llamarla. OC es un lenguaje dinámico, lo que significa que requiere no solo un compilador, sino también un sistema de ejecución para crear dinámicamente clases y objetos, pasar y enviar mensajes
1. Reenvío de mensajes
La característica principal de Runtime es el paso de mensajes. Si el mensaje no se puede encontrar en el objeto, se reenviará. Objective-C es un lenguaje dinámico, lo que significa que requiere no solo un compilador sino también un sistema de ejecución para crear clases y objetos dinámicamente, pasar y reenviar mensajes. El núcleo del tiempo de ejecución es el paso de mensajes.
(1) Proceso de paso de mensajes
Para un método de objeto [obj test], el compilador lo convierte en un mensaje y lo envía objc_msgSend(obj, test). El proceso es el siguiente
a. Primero encuentre su clase a través del puntero isa de obj
b. Busque la prueba en la lista de métodos de la clase
si la prueba no es así. encontrada en la clase, continúe buscando en su superclase
d Una vez que se encuentre la función de prueba, ejecute su IMP
Debido a problemas de eficiencia, no es razonable atravesar objc_method_list una vez por vez. cada mensaje, por lo que es necesario almacenar en caché las funciones llamadas con frecuencia para mejorar la eficiencia de la consulta de funciones. Esto es lo que hace objc_cache, otro miembro importante de objc_class. Después de encontrar la prueba, use el nombre_método de la prueba como clave y método_imp como valor. Cuando se reciba nuevamente el mensaje de prueba, podrá buscarlo directamente en el caché.
Objeto de clase (objc_class)
La clase Objective-C está representada por el tipo Clase, que en realidad es un puntero a la estructura objc_class. Hay muchas variables definidas en la estructura struct objc_class. La estructura almacena el puntero a la clase principal, el nombre de la clase (name), la versión, la lista de variables de instancia (ivars), la lista de métodos (methodLists), el caché (cache) y la lista de protocolos a cumplir (protocolos). De esto se puede ver que un objeto de clase es una estructura struct objc_class, y los datos almacenados en esta estructura son metadatos
Comprender Runtime es comprender su almacenamiento de datos y sus clases, instancias, objetos de clase y metaclases cuando iOS se está ejecutando relaciones y funciones.
(2) Mecanismo de reenvío de mensajes
En última instancia, la esencia de todas las llamadas a métodos en Objective-C es enviar mensajes a objetos
1. Crear métodos en clases -(void)test
2. El sistema iOS crea un número para este método, SEL(test) y lo agrega a la lista de métodos
3. Cuando esto Se llama al método, el sistema busca este método en la lista de métodos y lo ejecuta cuando lo encuentre
Por lo tanto, llamar a un método enviará un mensaje una vez, es decir, buscar en la lista de métodos de esta clase Si no se encuentra en la clase, vaya a Buscar en la clase principal de esta clase. Si no se puede encontrar la clase principal, busque hasta la raíz del árbol de herencia o reenvíe el mensaje. no tiene éxito, se informará un error de selector no reconocido.
1. Resolución de método dinámico
El tiempo de ejecución de Objective-C llamará a +resolveInstanceMethod: o? +resolveClassMethod: para darle la oportunidad de proporcionar una implementación de función si agrega una función. y devuelve SÍ, entonces el tiempo de ejecución reiniciará el proceso de envío de mensajes. Como se muestra a continuación:
Aunque no existe una función de implementación de foo:, la función fooMethod se agrega dinámicamente a través de class_addMethod(), y esta función se ejecuta e imprime con éxito. Si reslove devuelve NO, el tiempo de ejecución pasará al siguiente paso: forwardingTargetSelector
2. Reenvío de mensajes directos
Si el objeto de destino implementa forwardingTargetSelector, Runtime llamará a este método en este momento para brinde su oportunidad de reenviar este mensaje a otros objetos
Como se puede ver en la figura, hemos implementado el método de la clase actual en la clase padre a través del método forwardingTargetForSelector y la impresión se realizó correctamente.
3. Completar el reenvío de mensajes
Si el mensaje desconocido no se puede procesar en el paso anterior, lo único que se puede hacer es iniciar el mecanismo de reenvío de mensajes. Primero enviará el mensaje métodoSignatureForSelector para obtener el parámetro de la función y los tipos de valor de retorno. Si métodoSignatureForSelector devuelve cero, el tiempo de ejecución emitirá didNotRecognizeSelector. Si se devuelve una función firmada, Runtime creará un objeto NSInvocation y enviará un mensaje forwardInvocation al objeto de destino.
Aplicación práctica de Runtime
1. Utilice el método de intercambio de Runtime
2 Método de adición dinámica (no muy entendido en este momento)
4. Reenvío de mensajes (actualización en caliente) para solucionar errores (JSPatch)