OC笔记之Runtime

1.什么是Runtime?

OC是一门动态语言,它将很多操作推迟到运行时再进行,所以光有编译器是不够,还需要一个运行时系统,而Runtime就是OC的运行时机制,它是一套由C、C++、汇编编写的API,封装了很多动态性相关的函数。在我们平时编写的OC代码,在程序运行过程中,其实最终都转成了Runtime的C语言方法。

2.方法的本质是什么?runtime的消息机制

方法的本质就是发送消息。
发送消息的详细流程:方法调用转化为 objc_msgSend(id self, SEL _cmd, ...)

  • 首先会进行汇编快速查找:objc_object(对象) --> isa_t(isa) -->objc_class(类对象) --> cache_t(cache) --> bucketsbucket_t中存储了_sel_impcache_t使用了哈希算法,解决哈希冲突使用了开放寻址法,将cache_t结构体中的masksel进行与运算找到对应的imp
  • 慢速查找:objc_class(类对象) --> objc_method_list(methodLists)-->objc_method遍历查找,递归自己和父类查找方法lookUpImpOrForward
  • 查找不到消息,进行动态方法解析resolveInstanceMethod,方法内部会检查对象是否实现了+(BOOL)resolveInstanceMethod:(SEL)sel,因此可在此方法中为sel添加一个imp,此方法返回YES/NO只影响debug日志
  • 消息快速转发:- (id)forwardingTargetForSelector:(SEL)aSelector提供一个消息接收者对象
  • 消息慢速转发:消息签名- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector- (void)forwardInvocation:(NSInvocation *)anInvocation
  • 若消息最终都没有被处理会报错unrecoginzed selector send to instance xxx
3.SEL是什么?IMP是什么?两者有什么联系?
  • SEL是方法编号,即方法名称,在dyld加载镜像时,通过map_images-->map_images_nolock-->_read_images方法加载到内存的表中,而IMP是函数实现的指针
4.runtime的应用场景
  • 用于方法交换 MethodSwizzling,改变已存在的selector的实现,例如改变基类的方法实现app的统一配置,这里一般是在 +load方法中,且为了保证方法交换只执行一次使用dispatch_once进行包装
  • 实现给分类添加属性,尤其是系统类,利用Runtime的关联对象可为分类添加新的属性
  • 实现字典转模型如YYModel,利用Runtime的api获取属性列表,赋值等操作
  • 获取类的所有属性/方法名称,使用Runtime的apiclass_copyIvarListclass_copyMethodList
  • aspect切面编程
5.能否在分类中添加属性和成员变量?能否向已存在的类添加实倒变量?
  • 分类的结构体中没有属性列表,只有方法列表,原则上只能添加方法,不能添加属性,但是可以借助运行时关联对象。
  • 分类中可以使用@property, 但是不会生成setter/getter方法,也不会生成私有的成员变量,编译可以通过但引用就会报错。
  • 编译后的类已经注册在runtime中,类结构体中的objc_ivar_list实例变量的链表和instance_size实例变量的内存大小已经确定,同时runtime还会调用class_setIvarLayoutclass_setWeakIvarLayout来处理strongweak引用,所以不能向已存在的类中添加实例变量。但是运行时使用objc_allocateClassPair创建类,可以调用class_addIvar函数添加实例变量,但必须在调用objc_registerClassPair前。

你可能感兴趣的:(OC笔记之Runtime)