08.Objective-C 消息机制

2022-05-17  本文已影响0人  ProfessorFan

问题 消息机制的三个阶段

1.消息机制发送消息阶段-消息发送
2.消息机制动态方法解析阶段 -动态解析
3.消息机制消息转发阶段- 消息转发
4.线上项目中解决找不到方法奔溃

解决方案

1.消息机制发送消息阶段-消息发送
常用对象方法:
实例对象通过isa 指针 和 某一个值 发生一个位运算 得到该实例的类对象 ,类对象的两个方法列表中(cache_t,method_list_t )寻找对应的方法 如果没有找到,之后通过类对象的superClass 指针找到 父类的类对象中(cache_t,method_list_t)寻找,直到找到root类的类对象为止,这就是消息发送
常用类方法:
类对象通过isa 指针 和 某一个值 发生一个位运算 得到元类对象 ,元类的两个方法列表中(cache_t,method_list_t )寻找对应的方法 如果没有找到,之后通过元类对象的superClass 指针找到 父类的类对象中(cache_t,method_list_t)寻找,直到找到root元类的类对象为止,这就是消息发送

2.消息机制动态方法解析阶段 -动态解析
动态解析触发机制:
消息发送没有 找到对应的方法,就会出发消息的动态解析
a.动态解析C语言函数


void c_other(id self, SEL _cmd)
{
    NSLog(@"c_other - %@ - %@", self, NSStringFromSelector(_cmd));
}

+ (BOOL)resolveClassMethod:(SEL)sel
{
    if (sel == @selector(test)) {
        // 第一个参数是object_getClass(self)
        class_addMethod(object_getClass(self), sel, (IMP)c_other, "v16@0:8");
        return YES;
    }
    return [super resolveClassMethod:sel];
}
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    if (sel == @selector(test)) {
        // 动态添加test方法的实现
        class_addMethod(self, sel, (IMP)c_other, "v16@0:8");

        // 返回YES代表有动态添加方法
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

b.动态解析OC函数

- (void)other
{
    NSLog(@"%s", __func__);
}

+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    if (sel == @selector(test)) {
        // 获取其他方法
        Method method = class_getInstanceMethod(self, @selector(other));

        // 动态添加test方法的实现
        class_addMethod(self, sel,
                        method_getImplementation(method),
                        method_getTypeEncoding(method));

        // 返回YES代表有动态添加方法
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

3.消息机制消息转发阶段- 消息转发
消息转发触发机制:
动态解析 resolveInstanceMethod方法为 NO
a.消息转发函数

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    if (aSelector == @selector(test)) {
        // objc_msgSend([[MJCat alloc] init], aSelector)
        return [[MJCat alloc] init];
    }
    return [super forwardingTargetForSelector:aSelector];
}

b.如果消息转发函数也返回nil,现在就是方法签名

 方法签名:返回值类型、参数类型
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    if (aSelector == @selector(test)) {
        return [NSMethodSignature signatureWithObjCTypes:"v16@0:8"];
    }
    return [super methodSignatureForSelector:aSelector];
}

// NSInvocation封装了一个方法调用,包括:方法调用者、方法名、方法参数
 //   anInvocation.target 方法调用者
  //  anInvocation.selector 方法名
//    [anInvocation getArgument:NULL atIndex:0]
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
//    anInvocation.target = [[MJCat alloc] init];
//    [anInvocation invoke];

    [anInvocation invokeWithTarget:[[MJCat alloc] init]];
}

4.线上项目中解决找不到方法奔溃

@implementation NSBaseObject (bugSolve)

- (void)run
{
    NSLog(@"run-123");
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    // 本来能调用的方法
    if ([self respondsToSelector:aSelector]) {
       
        return [super methodSignatureForSelector:aSelector];
    }
    
    // 找不到的方法
    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}

// 找不到的方法,都会来到这里
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSLog(@"找不到%@方法", NSStringFromSelector(anInvocation.selector));
}

@end
上一篇下一篇

猜你喜欢

热点阅读