RunTime之消息转发

消息

在Objective-C中,消息是直到运行的时候才和方法实现绑定的。消息机制的关键在于编译器为类和对象生成的结构。每个类的结构中至少包括两个基本元素:

(1) 指向父类的指针
(2)类的方法表。方法表将方法选标和该类的方法实现的地址关联起来。
消息框架如下

RunTime之消息转发_第1张图片
消息框架.png

消息转发

当向someObject发送消息,但runtime system在当前类和父类中都找不到对应的方法实现时。runtime system并不会立即报错使程序崩溃,而是依次执行下列步骤:

RunTime之消息转发_第2张图片
步骤.png

分别简述一下流程:
(1) 动态方法解析 向当前类发送 resolveInstanceMethod: 或者 resolveClassMethod: 消息,检查是否动态向该类添加了方法。
(2)快速消息转发 检查该类是否实现了forwardingTargetForSelector: 方法,若实现了则调用该方法。若该方法返回值对象非nil或非self,则向该返回对象重新发送消息。
(3)标准消息转发 runtime发送methodSignatureForSelector:方法获取Selector对应的方法签名。返回值非nil则通过forwardInvocation:转发消息,返回值为nil则向当前对象发送doesNotRecognizeSelector:消息,程序崩溃退出。

示例

示例界面如下

RunTime之消息转发_第3张图片
示例主界面.png
#pragma mark - event response
- (void)dynamicBtnClicked:(id)sender
{
    self.dianDi86.name = @"DianDi86";
    NSLog(@"%@",self.dianDi86.name);
}

- (void)fastForwardBtnClicked:(id)sender
{
    [self.whiteHouse performSelector:@selector(setSex:) withObject:@"Boy"];
}

- (void)normalForwardBtnClicked:(id)sender
{
    [self.audioA4L performSelector:@selector(setSex:) withObject:@"Boy"];
}

动态方法解析

#import "People.h"
#include 

void dynamicSetNameIMP(id self, SEL _cmd, NSString *name)
{
    NSLog(@"%@ %@",self, NSStringFromSelector(_cmd));
    
    if (((People*)self)->_name != name) {
        ((People*)self)->_name = [name copy];
    }
}

NSString* dynamicNameIMP(id self, SEL _cmd)
{
    NSLog(@"%@ %@",self, NSStringFromSelector(_cmd));
    return ((People*)self)->_name;
}

@implementation People

@dynamic name;

+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    if (sel == @selector(setName:)) {
        class_addMethod(self, sel, (IMP)dynamicSetNameIMP, "v@:@");
        
        return YES;
    } else if (sel == @selector(name)) {
        class_addMethod(self, sel, (IMP)dynamicNameIMP, "@@:");
        
        return YES;
    }
    
    return [super resolveInstanceMethod:sel];
}

@end

点击示例界面中的动态方法解析console log 如下

RunTime之消息转发_第4张图片
动态解析.png

快速消息转发

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    // House 类需要将消息转发给People
    NSLog(@"%@ %@",self, NSStringFromSelector(_cmd));
    if ([self.master respondsToSelector:aSelector]) {
        return self.master;
    }
    
    return nil;
}

点击示例界面中的快速消息转发console log 如下

快速消息转发.png

标准消息转发

- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector
{
    NSLog(@"%@ %@",self, NSStringFromSelector(_cmd));
    NSMethodSignature *sign = [super methodSignatureForSelector:aSelector];
    if (sign == nil) {
        sign = [self.master methodSignatureForSelector:aSelector];
    }
    
    return sign;
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSLog(@"%@ %@",self, NSStringFromSelector(_cmd));
    SEL selector = [anInvocation selector];
    if ([self.master respondsToSelector:selector]) {
        [anInvocation invokeWithTarget:self.master];
    }
    
}

点击示例界面中的快速消息转发console log 如下

标准消息转发.png

你可能感兴趣的:(RunTime之消息转发)