1 runtime简介
- RunTime简称运行时。OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制。
- 对于C语言,函数的调用在编译的时候会决定调用哪个函数。
对于OC的函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。 - 事实证明:
在编译阶段,OC可以调用任何函数,即使这个函数并未实现,只要声明过就不会报错。
在编译阶段,C语言调用未实现的函数就会报错。
2 消息机制验证
- 2.1 在xcode中创建一个Command Line(命令行)工程,在main.m文件中写上以下两句代码:
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 创建并初始化一个object对象
NSObject *object= [NSObject alloc];
object = [object init];
}
return 0;
}
- 2.2 OC代码转换成C++格式
- cd /Users/Desktop/Clang 进入到main.m所在的文件夹
- clang -rewrite-objc main.m 执行此命令,将oc转化成C++
此时文件夹中多了一个main.cpp文件 - 打开main.cpp,发现main.m文件转化成了10多万行C++代码,以下是被转换后的main函数中的代码:
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
NSObject *object= ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc"));
object = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)object, sel_registerName("init"));
}
return 0;
}
alloc对应的函数 : objc_msgSend(objc_getClass("NSObject"), sel_registerName("alloc"));
init对应的函数: objc_msgSend(object, sel_registerName("init"));
// 第一个参数:谁发送消息,类名
// 第二个参数:发送一个什么样的消息,方法名
3 objc_msgSend方法的使用
- 导入头文件#import <objc/message.h>
- 取消objc_msgSend方法使用的限制
xcode6以后,苹果不希望我们使用runtime,对objc_msgSend实行了注释,如下:
OBJC_EXPORT void objc_msgSend(void /* id self, SEL op, ... */ )
要想使用runtime方法,需要进行如下配置:
- 使用举例
- 举例1:
// OC写法:
NSObject *objc = [NSObject alloc];
objc = [objc init];
// 纯runtime写法
NSObject *objc = objc_msgSend(objc_getClass("NSObject"), sel_registerName("alloc"));
objc = objc_msgSend(objc, sel_registerName("init"));
// runtime与OC的混合写法
NSObject *objc = objc_msgSend([NSObject class]), @selector(alloc));
objc = objc_msgSend(objc, @selector(init));
备注:
// 谁的事情谁开头 -> 对象(objc)
// objc_getClass(<#const char *name#>):根据类名获取类对象
// 类方法用类对象,对象方法用对象
- 举例2:
(1)场景:创建一个person类,并实现两个私有方法(没有声明的方法):
- (void)eat{
NSLog(@"吃东西");
}
- (void)run:(NSString *)name metre:(int)metre
{
NSLog(@"%@跑了%d米", name ,metre);
}
(2)实现过程代码
// 分配内存
Person *p = objc_msgSend([Person class], @selector(alloc));
// 初始化
p = objc_msgSend(p, @selector(init));
// 调用eat方法(没有参数)
objc_msgSend(p, @selector(eat));
// 调用run方法(有参数)
objc_msgSend(p, @selector(run:metre:),@"小明", 100);
4 消息机制使用场景
- 1.封装自己框架,尽量少的暴露接口,装逼用
- 2.调用私有的方法,前提:知道已经实现,只是没有声明暴露出来
网友评论