Runtime运行时

编译时运行时

编译时 顾名思义就是正在编译的时候 . 那啥叫编译呢?就是编译器帮你把
源代码翻译成机器能识别的代码 .
运行时 就是代码跑起来了.被装载到内存中去了 .

Runtime版本

Runtime有两个版本 一个Legacy版本(早期版本) ,一个Modern版本(现行版本)

  • 早期版本对应的编程接口:Objective-C 1.0
  • 现行版本对应的编程接口:Objective-C 2.0
  • 早期版本用于Objective-C 1.0, 32位的Mac OS X的平台上
  • 现行版本:iPhone程序和Mac OS X v10.5 及以后的系统中的 64 位程序

Runtime调用三种方式

1.Objective-C Code方式,例如[person sayHello]
2.Framework&Serivce 方式,例如isKindofClass
3.Runtime API方式,例如class_getInstanceSize

image.png

方法的底层实现

查看c++源码

创建一个类LKTeacher,以及LKPerson继承自LKTeacherLKTeacher添加实例方法teacherayHelloLKPerson添加实例方法personSayHello和类方法classSayHello

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        LKPerson *person = [LKPerson alloc];
        [person personSayHello];
        [person teacherayHello];
        [LKPerson classSayHello];
    }
    return 0;
}
复制代码

通过clangmain.m文件编译成main.cpp文件

clang -rewrite-objc main.m -o main.cpp
复制代码

查看main.cpp文件

static void _I_LKTeacher_teacherSayHello(LKTeacher * self, SEL _cmd) {
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_07_zf2hbch50bn79j6p806fy1t80000gn_T_main_0a11ef_mi_0);
}

static void _I_LKPerson_personSayHello(LKPerson * self, SEL _cmd) {
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_07_zf2hbch50bn79j6p806fy1t80000gn_T_main_64ea0d_mi_1);
}

static void _C_LKPerson_classSayHello(Class self, SEL _cmd) {
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_07_zf2hbch50bn79j6p806fy1t80000gn_T_main_64ea0d_mi_2);
}

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        LKPerson *person = ((LKPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("LKPerson"), sel_registerName("alloc"));
        ((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("personSayHello"));
        ((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("teacherSayHello"));
        ((void (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("LKPerson"), sel_registerName("classSayHello"));
    }
    return 0;
}
复制代码

可以看到,方法的实现都是通过objc_msgSend方式实现,既然如此,我们是否可以直接通过objc_msgSend发送消息来调用方法了。

objc_msgSend((id)person, sel_registerName("personSayHello"));
复制代码

必须导入相应的头文件#import <objc/message.h>
关闭objc_msgSend检查机制:target –> Build Setting –>搜索objc_msgSend — Enable strict checking of obc_msgSend calls设置为NO

通过objc_msgSend[person personSayHello]结果是一样的。
总结:方法的本质就是消息发送

父类方法的调用

上面可以看出,[person teacherayHello]可以直接调用到父类的方法。那么父类方法的调用又是怎么样的流程了。
LKPerson.m文件转换为LKPerson.cpp文件

((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("LKPerson"))}, sel_registerName("teacherSayHello"));
复制代码

可以看到[super teacherayHello]是通过objc_msgSendSuper实现的。可以看出objc_msgSendSuper的参数objc_super

struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained _Nonnull id receiver;

    /// Specifies the particular superclass of the instance to message. 
#if !defined(__cplusplus)  &&  !__OBJC2__
    /* For compatibility with old objc-runtime.h header */
    __unsafe_unretained _Nonnull Class class;
#else
    __unsafe_unretained _Nonnull Class super_class;
#endif
    /* super_class is the first class to search */
};
复制代码

子类通过objc_msgSendSuper方式调用父类的方法,方法的本质还是消息发送。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享