4.动态运行时(RunTime)
- 基础数据结构
- 对象、类对象、元类对象是怎么理解的?以及他们之间的关系是怎样的(实例与类对象之间的关系以及类对象与元类对象之间的关系)?
- OC语言中的消息传递机制是怎样的?
- 缓存查找 (我们进行方法查找的过程当中,如何进行缓存的方法查找?会使用到系统或者说Runtime中一个方法缓存的机制,这个机制又是怎样运行的呢?)
- 消息转发流程是怎样的?
- Method-Swizzling(方法混写)是Runtime的一种运用(我们可以再运行时,去替换一些方法的实现,也得益于动态运行时这一个特性),可能会结合实际的场景,比如说通过时长统计框架这样的考察来了解对于Runtime的Methood-Swizzling技术的一个实际的运用
- 动态添加方法(Runtime提供的功能实现)
- 动态方法解析(Runtime提供的功能实现)
动态添加方法
你是否有使用过performSelector这个系统方法(performSelector应用场景)?
void testImp (void)
{
NSLog(@"test invoke");
}
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
// 如果是test方法 打印日志
if (sel == @selector(test)) {
NSLog(@"resolveInstanceMethod:");
// 动态添加test方法的实现
/*参数:为哪个类添加方法,
添加方法对应的选择器名称,
方法的具体实现,
方法所对应的返回值类型以及参数的个数和每个参数的类型
v 函数的返回值为void @当前对象 : sel这个类型
*/
class_addMethod(self, @selector(test), testImp, "v@:");
return YES;
}
else{
// 返回父类的默认调用
return [super resolveInstanceMethod:sel];
}
}
1.一个类在编译时没有某个方法,在运行时才产生了这个方法,
就需要调用performSelector来调用这个方法,面试官借用这个来考察Runtime动态添加方法的特性.
上面的例子,我们调用了test,却没有实现它,所以需要在运行时去添加它的实现
在resolveInstanceMethod为test方法(选择器)添加具体实现
Runtime-动态方法解析
你是否使用过@dynamic这样一个编译器关键字?
1.当我们把声明的属性在实现中将它标识为@dynamic,就相当于get方法和set方法是在运行时添加,而不是在编译时声明好还有具体的实现,实际也是考察Runtime的相关内容
2.编译时语言和动态运行时语言的区别
- 动态运行时语言将函数决议推迟到运行时,实际上就是在运行时再去为方法添加具体的执行函数
当我们把属性标识为@dynamic时,代表着不需要编译器在编译时为我们生成这个属性的get方法和set方法的具体实现,
而是在运行时当我们具体的调用了get和set方法时,再去为它添加具体实现,只有动态运行时语言支持这种功能 - 编译时语言是在编译期进行函数决议,在编译期就决定了具体实现,在运行时无法修改
RunTime实战:
1、[obj foo]和objc_msgSend()函数的关系([obj foo](消息传递或者说发送消息,向obj对象发送foo这条消息),它和objc_msgSend()这个函数有什么关系)?
- [obj foo]在经过编译器处理之后,就变成了objc_msgSend()函数,这个参数第一个是obj,第二个参数是foo选择器
- 由于[obj foo]这个方法没有其他参数,所以objc_msgSend()这个函数参数只有两个
在编译之后呢,就把[obj foo]转化成objc_msgSend()这个函数调用了,
接下来就开始了Runtime的消息传递过程
2.runtime如何通过Selector找到对应的IMP地址?
- 其实就是消息传递机制本质,先查找当前实例对应类对象的缓存,
是否有Selector对应的缓存IMP实现,若有,则返回给调用方。
若没有,再根据当前类的方法列表,去查找Selector找到对应的IMP,
当前类如果没有,再根据当前类的superClass指针逐级查找父类方法列表,然后查找Selector所对应的IMP实现
3.能否向编译后的类中增加实例变量?
- runtime支持在运行时动态添加类,要注意是编译后的类还是动态添加的类
- 编译前创建的类,已经完成了实例变量的布局,在具体分析RunTime的数据结构当中知道class_ro_t,因为是readonly,所以在编译后是无法修改的,所以编译后的类,不能为他增加实例变量
4.能否向动态添加的类中增加实例变量?
- 但是可以向动态添加的类中添加实例变量,
- 因为在动态添加类的过程中,只要调用它的注册类对方法之前,完成实例变量的添加,就可以实现。