Runtime message forwarding

table of Contents

Flow chart of message forwarding:

1. Dynamic method analysis

2. Fast forwarding

3. Slow forwarding 

demo ruins


   The instance object in OC calls a method called发送消息

When sending a message to an object, if neither the method list of the object nor the method list on its corresponding inheritance chain can find the method implementation of the message, the message forwarding mechanism will be triggered.

   For example, the following code:

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject

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

@end

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

There is a method declared in the .h file, this method is not implemented in .m, and Person calls this unimplemented method, which triggers the message forwarding mechanism.

The Person object calls the sendMessage: method. The underlying implementation of OC is actually as follows


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

There is no way to implement it, we call it, and the message forwarding mechanism is like looking up a dictionary when we encounter unrecognized words. sendMessage: Where to find the method, objc_msgSend finds it in the [Person new] dictionary, the radical is the method number @selector, to find the word @"hello".

We look at the lookup process of the isa pointer:

Find the class through the isa pointer of the current object, find the method in the method list, and implement it directly, if there is no in the current list, look for it along the inheritance tree, and find the method implementation through the mapping relationship between the method number and IMP; if None, this time we enter the message forwarding mechanism.

Flow chart of message forwarding:

Flow of message forwarding mechanism

 

1. Dynamic method analysis

The first step: After the object receives an uninterpretable message, it will first call +(BOOL)resolveInstanceMethod:(SEL)sel
or + (BOOL)resolveClassMethod:(SEL)sel, and ask if there is a dynamically added method for processing and processing Examples are as follows


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

 Dynamic method analysis is to add a processing method


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

v@:@ This means that v indicates that the return value is of void type. The parameter id self of the above method is represented by @ , and the id type is represented by @ , SEL is the method number, represented by a colon :, and the parameter NSString type passed by ourselves is represented by @ . (id self, SEL _cmd, are the default parameters)

After running, we see that the message hello is printed.

2. Fast forwarding

If the implementation of the called method is not found in the first step of message forwarding at runtime, then the current receiver has a second chance to process it. At this time, the runtime system will call the -(id)forwardingTargetForSelector:(SEL)aSelector method, which can return an object that can be processed, and the runtime system will search based on the returned object, and if found, jump to the implementation of the corresponding method , The message forwarding ends.

Fast forwarding is plain, find a recipient

-(id)forwardingTargetForSelector:(SEL)aSelector {

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

The sendMessage: method has been implemented in the .m of the receiver we are looking for

#import "SpareWheel.h"

@implementation SpareWheel

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

}
@end

The results are as follows:

3. Slow forwarding 

  1. Method signature 
  2. Message forwarding

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

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

The above method signature information will be stored in NSInvocation, and the method number can be obtained through 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];
	}
}

The results are as follows:

Slowly forward the running results

If none of the above methods are implemented, the -(void)doesNotRecognizeSelector:(SEL)aSelector method will be executed. In order to prevent the program from crashing, you can write this way to increase the robustness of the program.

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

 

demo ruins

This article message forwarding demo address

 

 

 

 

Guess you like

Origin blog.csdn.net/zjpjay/article/details/86621055