10.ios-runtime 初探 消息转发流程

302 阅读2分钟

小技巧

  • 我想知道有哪些方法插入到缓存中了 image.png

image.png

image.png

image.png

image.png

  • 这里呢要打开隐藏文件夹的显示 shift + command + . image.png

image.png

  • 开始研究这个方法做了什么 image.png

image.png

image.png

测试一下这个方法能不能走

  • 1.创建一个类声明一个未实现的方法 image.png
  • 2.在.m文件中实现这个方法。 image.png
- (id)forwardingTargetForSelector:(SEL)aSelector{
    NSLog(@"%s - %@",__func__,NSStringFromSelector(aSelector));
    return nil;
}

  • 3.虽然结果是报错的但是这个方法是调用的 image.png

  • 4.现在创建另一个类并实现这个方法。

image.png

image.png

  • 5.引入这个类,并将这个方法的返回值为新建对象 image.png

  • 6.结果为成功的实现了另外的类的方法调用 image.png

  • OC调用方法的流程 通过 sel->imp

    • 1.objc_msgSend 查找缓存
    • 2.慢速查找 methodList
    • 3.动态方法决议
    • 4.runtime机制 让别的类调用同方法名的方法做这个事情。

快速转发

// 快速转发
- (id)forwardingTargetForSelector:(SEL)aSelector{
    NSLog(@"%s - %@",__func__,NSStringFromSelector(aSelector));
    return nil;
}

- (id)forwardingTargetForSelector:(SEL)aSelector{
    return [LGStudent alloc];
}
  • 加入我们所返回的类也没有这个方法的实现,则需要慢速转发 需要methodSignatureForSelector方法配合forwardInvocation使用

慢速转发

image.png

image.png

//// 慢速转发
//返回一个方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    NSLog(@"%s - %@",__func__,NSStringFromSelector(aSelector));
    if (aSelector == @selector(sayHello)) {
        //返回一个方法签名
        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}
  • 这个方法暂时不实现时
- (void)forwardInvocation:(NSInvocation *)anInvocation{
    NSLog(@"%@ - %@",anInvocation.target,NSStringFromSelector(anInvocation.selector));
}
  • 发现程序并没有奔溃同时记录了对象调用的方法。这里可以作为错误日志的搜集记录。 image.png

  • 这里提示我们如果这个方法要实现就需要重写methodSignatureForSelector image.png
- (void)forwardInvocation:(NSInvocation *)anInvocation{
//    NSLog(@"%@ - %@",anInvocation.target,NSStringFromSelector(anInvocation.selector));
    LGStudent *s = [LGStudent alloc];
    //判断我自己self 能够处理这个方法
    if ([self respondsToSelector:anInvocation.selector]) {
        [anInvocation invoke]; //直接调用invoke
    }else if ([s respondsToSelector:anInvocation.selector]){
        //判断别的类能够处理这个方法
        [anInvocation invokeWithTarget:s];
    }else{
        //上传日志这里发生了奔溃
        NSLog(@"%s - %@",__func__,NSStringFromSelector(anInvocation.selector));
    }
}

image.png

探索思路,路是坎坷的,入门到放弃。

  • 1.bt打印查看编译栈流程 发现目标在 CoreFoundation 中 image.png

  • 2.搜索查找 CF源码无果 image.png

  • 3.CoreFoundation 查找CoreFoundation开源源码

  • 4.选择下载一个 image.png

最后找到一个CoreFoundation的开源动态库,哈哈哈哈哈哈我不会找。老师给的,网上找找应该是有的吧。


反汇编流程

  • 将可执行文件给Hopper打开

image.png

image.png

image.png image.png

  • 进入 forwarding

    • 这里是判断失误跳转到loc_64a67忽略不看 image.png
  • 结构存入到rax寄存器中。rax = _objc_msgSend(rdi,r14); image.png

  • 继续往下运行查找下层的消息接收者 image.png

image.png

image.png

KC消息转发机制.png

Cooci_消息转发机制.png