Utilice NSInvocation para enviar mensajes a objetos
?La función de reenvío de nivel más bajo es objc_msgSend, que se define de la siguiente manera
De la definición anterior, podemos concluir que un reenvío de mensajes contiene varios elementos principales: destino, selector, argumentos. , valor de retorno, objc_msgSend es una función de C, Apple no nos recomienda usar esta función directamente para enviar mensajes a objetos.
Todos deben saber que performSelector se usa para enviar mensajes a objetos, pero tiene varias deficiencias.
NSInvocation es un sistema de reenvío de mensajes de alto nivel proporcionado por los ingenieros de Apple. Es un objeto de comando que puede enviar mensajes a cualquier tipo de objeto Objective-C. El uso de NSInvocation se presentará a continuación.
El método de fábrica invocationWithMethodSignature: debe usarse para crear una instancia de NSInvocation. El parámetro del método de fábrica es un objeto NSMethodSignature. Generalmente, el método de instancia de NSObject métodoSignatureForSelector: o el método de clase instanciaMethodSignatureForSelector: se utiliza para crear un objeto NSMethodSignature correspondiente al selector.
Ejemplo: Crear firma de método de clase y firma de método de instancia
Cabe señalar que el objeto NSMethodSignature solo representa la firma del método: la solicitud del método y la codificación del datos devueltos. Por lo tanto, después de usar NSMethodSignature para crear un objeto NSInvocation, aún necesita especificar el objeto receptor del mensaje y el selector.
El principio es que el selector correspondiente del objeto receptor debe coincidir con NSMethodSignature. Sin embargo, según la práctica, siempre que no exista una excepción NSInvocation setArgument: atIndex fuera de límites, el mensaje se puede reenviar con éxito y, después de un reenvío exitoso, todos los parámetros no asignados se asignarán a cero.
Por ejemplo:
Resultado de la ejecución:
Las anteriores son las operaciones para los parámetros definidos en la clase NSInvocation. El parámetro argumentLocation es de tipo void *, lo que significa que se le debe pasar la dirección del puntero. El parámetro idx comienza desde 2, y 0 y 1 representan el objetivo y el selector respectivamente. Aunque puede usar getArgument: atIndex directamente para obtener el objetivo y el selector, no es tan conveniente como los atributos de destino y selector de NSInvocation. Cabe señalar que cuando idx excede la cantidad de parámetros correspondientes a NSMethodSignature, los métodos para obtener parámetros y configurar parámetros arrojarán excepciones NSInvalidArgumentException.
Por ejemplo: pasar parámetros al método GreetingWithName:
Se debe prestar especial atención a setArgument: atIndex: su argumento no tendrá una fuerte referencia de forma predeterminada si el argumento se publica antes de NSInvocation. se ejecuta, provocará una excepción de puntero salvaje (EXC_BAD_ACCESS).
Como se muestra en la figura anterior, la invocación no hace referencia fuerte a su objetivo. Después de que aparece el controlador, el objetivo se libera y luego invocar esta invocación provocará una excepción de puntero salvaje. Llame al método retenciónArguments para hacer referencia fuerte a los parámetros (incluidos el destino y el selector).
El método para devolver datos en la clase NSInvocation es el siguiente
Puede ver que los datos devueltos aún pasan el valor a través del puntero entrante. Ejemplo:
El resultado de salida es:
Cabe señalar que: considerando que el método getReturnValue solo copia los datos devueltos en el área de búfer proporcionada (retLoc), no toma Tenga en cuenta la gestión de la memoria aquí, por lo que si los datos devueltos son de tipo objeto, los datos devueltos realmente obtenidos son del tipo __unsafe_unretained. Cuando la función de capa superior los devuelve como datos de retorno, se producirá una excepción de puntero salvaje. Hay dos soluciones comunes:
La primera: crear un nuevo objeto del mismo tipo y señalarlo. De esta manera, el resultado tendrá una fuerte referencia a tempResult cuando se devuelvan los datos. la palabra clave de liberación automática se agregará automáticamente. No provocará excepciones de puntero salvaje.
El segundo método: use __bridge para convertir el área del búfer al tipo Objective-C. Este método es en realidad similar al primer método, pero recomendamos usar este método para resolver los problemas anteriores porque getReturnValue El original. El propósito es escribir datos en el área de caché. Es más razonable declarar el área de caché como tipo void* y luego convertirla al tipo Objective-C mediante el método __bridge y entregar la administración de memoria de esta área de memoria a ARC.