1.在需要使用runtime的地方导入#import<objc/message.h>。
如demo, LGPersoon类,有run方法申明,但无无实现
@interface LGPersoon : NSObject
- (void)run;
@end
如下图,说明OC是动态语言
我们来看下,main文件通过runtime编译成c语言的代码
终端执行,将.m生成C
clang -rewrite-objc main.m -o main.cpp
就成生成。cpp文件
OC对象的本质就是结构体
LGPersoon *p = [[LGPersoon alloc] init];
[p run];
方法的本质 - 发送消息
/// (void *)objc_msgSend)((id)p 消息接收者
/// sel_registerName("run") 方法编号
/// IMP函数实现的指针 --sel ->找到 IMP
/// 下层通讯 方法 -- 对象 --类
/// 父类
LGStudent *s = [LGStudent new];
// [s run];
/// 方法的调用底层编译
/// 方法的本质 : 消息: 消息接收者 消息编号 。。。 参数(消息体) 方法调用
((**void** *(*)(**id**, **SEL**))objc_msgSend)(s, sel_registerName("run"));
NSLog(@"%p --- %p", sel_registerName("run"), **@selector**(run));
NSLog(@"%p --- %p", sel_registerName("run"), @selector(run)); 你会发现。打印的方法编号是一样的
runtime-初探[86068:943153] 0x7fff6dd7b8bb --- 0x7fff6dd7b8bb
这说明@selector(run) 与 sel_registerName("run") 是等同的
问?有一个类对象,怎么调用对象不存在的方法,且编译不会报错
答: 那当然是使用runtime了
LGPersoon *p = [[LGPersoon alloc] init];
方法1: [p performSelector:@selector(walk)];
方法2: ((void ()(id, SEL))objc_msgSend)(p, sel_registerName("walk"));
方法3:
void *pointB = &p;
[( __bridge id)pointA walk];
类方法的调用
((void*(*)(id, SEL))objc_msgSend)(objc_getClass("LGStudent"), sel_registerName("run"));
向父类发送消息(对象方法)
struct objc_super mySuper;
mySuper.receiver = s;
mySuper.super_class = class_getSuperclass([s class]); /// 元类
((void*(*)(id, SEL))objc_msgSendSuper)((__bridge id)(&mySuper), @selector(run));
面试题
- 对象方法存在哪
类里面 - 类方法存在哪
元类里面 - 类方法存在 元类里面,哪方法是什么样的方式姿态存在
实例方法 /// 对象 是 类 的一个实例对象 对象的方法是以 实例方法的形式存在类 /// so 类对象 也是元类的 一个实例。 所以类方法 是以 实例方法的 姿态存在元类里面
// main.m
// runtime-初探
//#import <UIKit/UIKit.h>
//#import "AppDelegate.h"
#import "LGPersoon.h"
#import "LGStudent.h"
#import <objc/message.h>
// 代码--->编译连接---> 执行
// 对于C函数就是静态性,我编译如果不存在这个run函数,就会报错,但是OC不一样
**int** main(**int** argc, **char** * argv[]) {
// NSString * appDelegateClassName;
**@autoreleasepool** {
// Setup code that might create autoreleased objects goes here.
// appDelegateClassName = NSStringFromClass([AppDelegate class]);
LGPersoon *p = [[LGPersoon alloc] init];
// [p run];
// clang --rewrite-objc main.m -o main.cpp
/** 编译成c后的源码
LGPersoon *p = ((LGPersoon *(*)(id, SEL))(void *)objc_msgSend)((id)((LGPersoon *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("LGPersoon"), sel_registerName("alloc")), sel_registerName("init"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("run"));
*/
/// 方法的本质 - 发送消息
/// (void *)objc_msgSend)((id)p 消息接收者
/// sel_registerName("run") 方法编号
/// IMP函数实现的指针 --sel ->找到 IMP
/// 下层通讯 方法 -- 对象 --类
/// 父类
LGStudent *s = [LGStudent new];
// [s run];
/// 方法的调用底层编译
/// 方法的本质 : 消息: 消息接收者 消息编号 。。。 参数(消息体) 方法调用
((void *(*)(id, SEL))objc_msgSend)(s, sel_registerName("run"));
/// runtime
NSLog(@"%p --- %p", sel_registerName("run"), @selector(run));
/// 0x7fff6dd7b8bb --- 0x7fff6dd7b8bb 说明 sel_registerName("run") 等同于 @selector(run)
/// 类方法编译底层
id cls = [LGStudent class];
void *pointA = &cls;
void *pointB = &p;
[( __bridge id)pointA walk];
/// 使用&对象,然后 (__bridge id) 就可以调用方法了,编译不会报错。 (p 是不存在 walk 方法的);
// [(__bridge id)pointB walk];
// [p performSelector:@selector(walk)];
// ((void *(*)(id, SEL))objc_msgSend)(p, sel_registerName("walk"));
/// 类方法的调用
((void *(*)(id, SEL))objc_msgSend)(objc_getClass("LGStudent"), sel_registerName("run"));
/// 向父类发送消息(类方法)
struct objc_super mySuper;
mySuper.receiver = s;
mySuper.super_class = class_getSuperclass([s class]); /// 元类
((void *(*)(id, SEL))objc_msgSendSuper)((__bridge id)(&mySuper), @selector(run));
/// 面试题
/// 对象方法存在哪。- 答。类里面
/// 类方法存在哪。- 答。 元类
/// 面试题
/// 类方法存在 元类里面,哪方法是什么样的方式姿态存在 答: 实例方法
/// 对象 是 类 的一个实例对象 对象的方法是以 实例方法的形式存在类
/// so 类对象 也是元类的 一个实例。 所以类方法 是以 实例方法的 姿态存在元类里面
}
return 0;
}