Reenvío de mensajes en tiempo de ejecución

Tabla de contenido

Diagrama de flujo de reenvío de mensajes:

1. Análisis de método dinámico

2. Avance rápido

3. Avance lento 

ruinas de demostración


   El objeto de instancia en OC llama a un método llamado发送消息

Al enviar un mensaje a un objeto, si ni la lista de métodos del objeto ni la lista de métodos en su cadena de herencia correspondiente pueden encontrar la implementación del método del mensaje, se activará el mecanismo de reenvío de mensajes.

   Por ejemplo, el siguiente código:

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject

- (void)sendMessage:(NSString*)message;

@end

NS_ASSUME_NONNULL_END
Person *p = [[Person alloc]init];
[p sendMessage:@"hello"];

Hay un método declarado en el archivo .h, este método no está implementado en .m y Person llama a este método no implementado, que activa el mecanismo de reenvío de mensajes.

El objeto Person llama al método sendMessage :. La implementación subyacente de OC es en realidad la siguiente


 objc_msgSend([Person new],@selector(sendMessage:),@"hello");

No hay forma de implementarlo, lo llamamos, y el mecanismo de reenvío de mensajes es como buscar un diccionario cuando encontramos palabras no reconocidas. sendMessage: Donde encontrar el método, objc_msgSend lo encuentra en el diccionario [Person new], el radical es el número de método @selector, para encontrar la palabra @ "hello".

Observamos el proceso de búsqueda del puntero isa:

Busque la clase a través del puntero isa del objeto actual, busque el método en la lista de métodos e impleméntelo directamente, si no hay ninguno en la lista actual, búsquelo en el árbol de herencia y encuentre la implementación del método a través de la relación de mapeo entre el número de método y el IMP; si Ninguno, esta vez ingresamos al mecanismo de reenvío de mensajes.

Diagrama de flujo de reenvío de mensajes:

Flujo del mecanismo de reenvío de mensajes

 

1. Análisis de método dinámico

El primer paso: Después de que el objeto recibe un mensaje ininterpretable, primero llamará a + (BOOL) resolveInstanceMethod: (SEL) sel
o + (BOOL) resolveClassMethod: (SEL) sel, y preguntará si hay un método agregado dinámicamente para procesar y procesar Los ejemplos son los siguientes


+(BOOL)resolveInstanceMethod:(SEL)sel {
	// 方法匹配
	NSString *methodName = NSStringFromSelector(sel);
	if ([methodName isEqualToString:@"sendMessage:"]) {
		return class_addMethod(self, sel, (IMP)sendMessage, "v@:@");
	}
	return [super resolveInstanceMethod:sel];//如果没有就走继承树方法
}

 El análisis de método dinámico consiste en agregar un método de procesamiento


void sendMessage(id self,SEL _cmd,NSString* message) {
	NSLog(@"---%@",message);
}

v @: @ Esto significa que v indica que el valor devuelto es de tipo void. El parámetro id self del método anterior está representado por @ , y el tipo de id está representado por @ , SEL es el número de método, representado por dos puntos :, y el parámetro NSString tipo pasado por nosotros está representado por @ . (id self, SEL _cmd, son los parámetros predeterminados)

Después de ejecutar, vemos que se imprime el mensaje hola.

2. Avance rápido

Si la implementación del método llamado no se encuentra en el primer paso del reenvío de mensajes en tiempo de ejecución, entonces el receptor actual tiene una segunda oportunidad para procesarlo. En este momento, el sistema en tiempo de ejecución llamará al método - (id) forwardingTargetForSelector: (SEL) aSelector, que puede devolver un objeto que se puede procesar, y el sistema en tiempo de ejecución buscará basándose en el objeto devuelto y, si lo encuentra, saltará a la implementación del método correspondiente. , Finaliza el reenvío de mensajes.

El avance rápido es sencillo, busque un destinatario

-(id)forwardingTargetForSelector:(SEL)aSelector {

	NSString *methodName = NSStringFromSelector(aSelector);
			if ([methodName isEqualToString:@"sendMessage:"]) {
		return [SpareWheel new];//备用接受者
	}
	return [super forwardingTargetForSelector:aSelector];//走继承树方法
}

El método sendMessage: se ha implementado en el .m del receptor que estamos buscando

#import "SpareWheel.h"

@implementation SpareWheel

- (void)sendMessage:(NSString*)message {
	
	NSLog(@"---SpareWheel say %@",message);

}
@end

Los resultados son los siguientes:

3. Avance lento 

  1. Firma del método 
  2. Reenvío de mensajes

#pragma mark - 方法签名
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {

	NSString *methodName = NSStringFromSelector(aSelector);
	if ([methodName isEqualToString:@"sendMessage:"]) {
		return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
	}
	return [super methodSignatureForSelector:aSelector];
}

La información de la firma del método anterior se almacenará en NSInvocation, y el número de método se puede obtener a través de SEL sel = [anInvocation selector]

//这个方法是找一个 处理者
-(void)forwardInvocation:(NSInvocation *)anInvocation {
//消息转发
	SEL sel = [anInvocation selector];
	SpareWheel *tempObjc = [SpareWheel new];// 找一个处理者
	if ([tempObjc respondsToSelector:sel]) {
// 如果这个处理者响应了这个方法,就指定它作为目标对象,处理当前的方法
		[anInvocation invokeWithTarget:tempObjc];
	}else{
		[super forwardInvocation:anInvocation];
	}
}

Los resultados son los siguientes:

Avanza lentamente los resultados en ejecución

Si no se implementa ninguno de los métodos anteriores, se ejecutará el método - (void) doesNotRecognizeSelector: (SEL) aSelector. Para evitar que el programa se bloquee, puede escribir de esta manera para aumentar la solidez del programa.

//找不到方法就执行这个
-(void)doesNotRecognizeSelector:(SEL)aSelector {
	NSLog(@"找不到方法");
}

 

ruinas de demostración

Dirección de demostración de reenvío de mensajes de este artículo

 

 

 

 

Supongo que te gusta

Origin blog.csdn.net/zjpjay/article/details/86621055
Recomendado
Clasificación