美文网首页
Runtime触探学习笔记第一篇

Runtime触探学习笔记第一篇

作者: _Luyouli | 来源:发表于2020-08-21 15:58 被阅读0次

    Runtime触探学习笔记

    • runtime是一套API,由C和C++汇编一起写成的API,给我们的OC提供运行时.

    运行时

    • 运行时,代码在起来后装载内存,运行时功能就依赖于runtime

    编译时

    • 正在编译的时间,编译过程的主要工作就是将源代码翻译成可以识别的语言,我们使用的比如OC,Swift,java等属于高级语言,需要翻译成机器语言(最底层的二进制)

    1.首先我们要从OC对象的本质开始

    • OC的面向对象都是基于C/C++的结构体来实现的,OC对象、类的实质就是一个结构体
    typedef struct objc_object SYPerson;
    typedef struct {} _objc_exc_SYPerson;
    
    struct SYPerson_IMPL {
        struct NSObject_IMPL NSObject_IVARS;
    };
    
    • 方法的本质就是发送消息,消息:消息接受者 消息编号...参数(消息体)
    objc_msgSend(s,sel_registerName("run"));
    

    对于C函数而言就是静态性,如果我编译一个不存在的run函数就会直接报错,但是OC在编译阶段并不会报错,只会在运行时报错。比如在一个person对象中的.m文件中并没有实现run方法,但是在编译阶段不会错误,一旦运行后就会崩溃

    clang使用方式

    clang -rewrite-objc main.m -o main.cpp
    

    clang运行项目main会生成一个cpp文件,cpp文件中有下面这段关键代码

    int main(int argc, const char * argv[]) {
        /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
    
            SYPerson *person = ((SYPerson *(*)(id, SEL))(void *)objc_msgSend)((id)((SYPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("SYPerson"), sel_registerName("alloc")), sel_registerName("init"));
            ((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("run"));
            run();
    
        }
        return 0;
    }
    
    • (void *)objc_msgSend)((id)person 消息接收者
    • sel_registerName("run")) 方法编号
    • imp函数实现的指针 ---sel -> imp 如何进行下层通讯
    方法下层消息如何走的?对象方法和类方法分别是如何发起的?父类发送消息?
    • runtime的三种调用方式
      1.api
      2.NSObject (isKindOf)
      3.OC上层(@selector)

    对象发送消息

    SYPerson *me = [SYPerson new];
    [me run];
    ((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("run"));
    

    类方法在元类中以实例方法的姿态存在,类在元类中也是以实例存在

    id cls = [SYDog class];
    void *pointA = &cls;
    [(__bridge id)pointA walk];
    ((void (*)(id, SEL))(void *)objc_msgSend)(objc_getClass("SYDog"), sel_registerName("walk"));
     
    
    objc_msgSend 发送消息的两种方式
    • 快速:直接通过汇编中的缓存cache_t(imp哈希表)中去找,每一个类中都会缓存
    • 慢速:直接通过C/C++ 汇编一起完成的,找到后又存在缓存中
    • 为什么objc_msgSend要用汇编写是因为C语言写一个函数无法通过保留未知的参数跳转到任意的一个指针。第二个原因就是更快。

    相关文章

      网友评论

          本文标题:Runtime触探学习笔记第一篇

          本文链接:https://www.haomeiwen.com/subject/ghoujktx.html